From fa637abff0607ab50984db1ec97d78b110f04ef3 Mon Sep 17 00:00:00 2001 From: sepehr Date: Sun, 14 Jun 2026 16:44:18 +0200 Subject: [PATCH] perf+security: fix build, secure downloads, dedupe translations, refactor i18n 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). --- .env.example | 5 + .gitignore | 7 + docker-compose.monitoring.yml | 6 +- docker-compose.yml | 4 +- frontend/next.config.ts | 6 +- frontend/package.json | 4 +- frontend/pnpm-lock.yaml | 7833 +++++++++ frontend/src/lib/i18n.tsx | 14191 +--------------- frontend/src/lib/i18n/messages/ar/admin.json | 48 + .../src/lib/i18n/messages/ar/apiKeys.json | 72 + frontend/src/lib/i18n/messages/ar/auth.json | 3 + .../src/lib/i18n/messages/ar/checkout.json | 12 + frontend/src/lib/i18n/messages/ar/common.json | 4 + .../src/lib/i18n/messages/ar/context.json | 25 + .../lib/i18n/messages/ar/cookieConsent.json | 7 + .../src/lib/i18n/messages/ar/dashboard.json | 111 + .../lib/i18n/messages/ar/fileUploader.json | 31 + .../src/lib/i18n/messages/ar/glossaries.json | 189 + frontend/src/lib/i18n/messages/ar/index.ts | 56 + .../src/lib/i18n/messages/ar/landing.json | 146 + .../lib/i18n/messages/ar/langSelector.json | 7 + frontend/src/lib/i18n/messages/ar/layout.json | 5 + frontend/src/lib/i18n/messages/ar/login.json | 6 + .../src/lib/i18n/messages/ar/memento.json | 6 + .../src/lib/i18n/messages/ar/pricing.json | 151 + .../src/lib/i18n/messages/ar/profile.json | 58 + .../i18n/messages/ar/providerSelector.json | 7 + .../lib/i18n/messages/ar/providerTheme.json | 29 + .../src/lib/i18n/messages/ar/register.json | 29 + .../src/lib/i18n/messages/ar/services.json | 14 + .../src/lib/i18n/messages/ar/settings.json | 20 + .../src/lib/i18n/messages/ar/translate.json | 92 + .../i18n/messages/ar/translateComplete.json | 6 + frontend/src/lib/i18n/messages/de/admin.json | 48 + .../src/lib/i18n/messages/de/apiKeys.json | 72 + frontend/src/lib/i18n/messages/de/auth.json | 3 + .../src/lib/i18n/messages/de/checkout.json | 12 + frontend/src/lib/i18n/messages/de/common.json | 4 + .../src/lib/i18n/messages/de/context.json | 25 + .../lib/i18n/messages/de/cookieConsent.json | 7 + .../src/lib/i18n/messages/de/dashboard.json | 111 + .../lib/i18n/messages/de/fileUploader.json | 31 + .../lib/i18n/messages/de/forgotPassword.json | 14 + .../src/lib/i18n/messages/de/glossaries.json | 189 + frontend/src/lib/i18n/messages/de/index.ts | 60 + .../src/lib/i18n/messages/de/landing.json | 146 + .../lib/i18n/messages/de/langSelector.json | 7 + frontend/src/lib/i18n/messages/de/layout.json | 5 + frontend/src/lib/i18n/messages/de/login.json | 18 + .../src/lib/i18n/messages/de/memento.json | 6 + .../src/lib/i18n/messages/de/pricing.json | 151 + .../src/lib/i18n/messages/de/profile.json | 58 + .../i18n/messages/de/providerSelector.json | 7 + .../lib/i18n/messages/de/providerTheme.json | 29 + .../src/lib/i18n/messages/de/register.json | 29 + .../lib/i18n/messages/de/resetPassword.json | 22 + .../src/lib/i18n/messages/de/services.json | 14 + .../src/lib/i18n/messages/de/settings.json | 20 + .../src/lib/i18n/messages/de/translate.json | 92 + .../i18n/messages/de/translateComplete.json | 6 + frontend/src/lib/i18n/messages/en/admin.json | 48 + .../src/lib/i18n/messages/en/apiKeys.json | 72 + frontend/src/lib/i18n/messages/en/auth.json | 3 + .../src/lib/i18n/messages/en/checkout.json | 12 + frontend/src/lib/i18n/messages/en/common.json | 4 + .../src/lib/i18n/messages/en/context.json | 25 + .../lib/i18n/messages/en/cookieConsent.json | 7 + .../src/lib/i18n/messages/en/dashboard.json | 115 + .../lib/i18n/messages/en/fileUploader.json | 31 + .../lib/i18n/messages/en/forgotPassword.json | 14 + .../src/lib/i18n/messages/en/glossaries.json | 189 + frontend/src/lib/i18n/messages/en/index.ts | 60 + .../src/lib/i18n/messages/en/landing.json | 152 + .../lib/i18n/messages/en/langSelector.json | 7 + frontend/src/lib/i18n/messages/en/layout.json | 5 + frontend/src/lib/i18n/messages/en/login.json | 18 + .../src/lib/i18n/messages/en/memento.json | 6 + .../src/lib/i18n/messages/en/pricing.json | 151 + .../src/lib/i18n/messages/en/profile.json | 58 + .../i18n/messages/en/providerSelector.json | 7 + .../lib/i18n/messages/en/providerTheme.json | 29 + .../src/lib/i18n/messages/en/register.json | 29 + .../lib/i18n/messages/en/resetPassword.json | 22 + .../src/lib/i18n/messages/en/services.json | 14 + .../src/lib/i18n/messages/en/settings.json | 20 + .../src/lib/i18n/messages/en/translate.json | 93 + .../i18n/messages/en/translateComplete.json | 6 + frontend/src/lib/i18n/messages/es/admin.json | 48 + .../src/lib/i18n/messages/es/apiKeys.json | 72 + frontend/src/lib/i18n/messages/es/auth.json | 3 + .../src/lib/i18n/messages/es/checkout.json | 12 + frontend/src/lib/i18n/messages/es/common.json | 4 + .../src/lib/i18n/messages/es/context.json | 25 + .../lib/i18n/messages/es/cookieConsent.json | 7 + .../src/lib/i18n/messages/es/dashboard.json | 111 + .../lib/i18n/messages/es/fileUploader.json | 31 + .../lib/i18n/messages/es/forgotPassword.json | 14 + .../src/lib/i18n/messages/es/glossaries.json | 189 + frontend/src/lib/i18n/messages/es/index.ts | 60 + .../src/lib/i18n/messages/es/landing.json | 146 + .../lib/i18n/messages/es/langSelector.json | 7 + frontend/src/lib/i18n/messages/es/layout.json | 5 + frontend/src/lib/i18n/messages/es/login.json | 18 + .../src/lib/i18n/messages/es/memento.json | 6 + .../src/lib/i18n/messages/es/pricing.json | 151 + .../src/lib/i18n/messages/es/profile.json | 58 + .../i18n/messages/es/providerSelector.json | 7 + .../lib/i18n/messages/es/providerTheme.json | 29 + .../src/lib/i18n/messages/es/register.json | 29 + .../lib/i18n/messages/es/resetPassword.json | 22 + .../src/lib/i18n/messages/es/services.json | 14 + .../src/lib/i18n/messages/es/settings.json | 20 + .../src/lib/i18n/messages/es/translate.json | 92 + .../i18n/messages/es/translateComplete.json | 6 + frontend/src/lib/i18n/messages/fa/admin.json | 48 + .../src/lib/i18n/messages/fa/apiKeys.json | 72 + frontend/src/lib/i18n/messages/fa/auth.json | 3 + .../src/lib/i18n/messages/fa/checkout.json | 12 + frontend/src/lib/i18n/messages/fa/common.json | 4 + .../src/lib/i18n/messages/fa/context.json | 25 + .../lib/i18n/messages/fa/cookieConsent.json | 7 + .../src/lib/i18n/messages/fa/dashboard.json | 111 + .../lib/i18n/messages/fa/fileUploader.json | 31 + .../src/lib/i18n/messages/fa/glossaries.json | 189 + frontend/src/lib/i18n/messages/fa/index.ts | 56 + .../src/lib/i18n/messages/fa/landing.json | 146 + .../lib/i18n/messages/fa/langSelector.json | 7 + frontend/src/lib/i18n/messages/fa/layout.json | 5 + frontend/src/lib/i18n/messages/fa/login.json | 6 + .../src/lib/i18n/messages/fa/memento.json | 6 + .../src/lib/i18n/messages/fa/pricing.json | 151 + .../src/lib/i18n/messages/fa/profile.json | 58 + .../i18n/messages/fa/providerSelector.json | 7 + .../lib/i18n/messages/fa/providerTheme.json | 29 + .../src/lib/i18n/messages/fa/register.json | 29 + .../src/lib/i18n/messages/fa/services.json | 14 + .../src/lib/i18n/messages/fa/settings.json | 20 + .../src/lib/i18n/messages/fa/translate.json | 92 + .../i18n/messages/fa/translateComplete.json | 6 + frontend/src/lib/i18n/messages/fr/admin.json | 48 + .../src/lib/i18n/messages/fr/apiKeys.json | 72 + frontend/src/lib/i18n/messages/fr/auth.json | 3 + .../src/lib/i18n/messages/fr/checkout.json | 12 + frontend/src/lib/i18n/messages/fr/common.json | 4 + .../src/lib/i18n/messages/fr/context.json | 25 + .../lib/i18n/messages/fr/cookieConsent.json | 7 + .../src/lib/i18n/messages/fr/dashboard.json | 115 + .../lib/i18n/messages/fr/fileUploader.json | 31 + .../lib/i18n/messages/fr/forgotPassword.json | 14 + .../src/lib/i18n/messages/fr/glossaries.json | 189 + frontend/src/lib/i18n/messages/fr/index.ts | 60 + .../src/lib/i18n/messages/fr/landing.json | 152 + .../lib/i18n/messages/fr/langSelector.json | 7 + frontend/src/lib/i18n/messages/fr/layout.json | 5 + frontend/src/lib/i18n/messages/fr/login.json | 18 + .../src/lib/i18n/messages/fr/memento.json | 6 + .../src/lib/i18n/messages/fr/pricing.json | 151 + .../src/lib/i18n/messages/fr/profile.json | 58 + .../i18n/messages/fr/providerSelector.json | 7 + .../lib/i18n/messages/fr/providerTheme.json | 29 + .../src/lib/i18n/messages/fr/register.json | 29 + .../lib/i18n/messages/fr/resetPassword.json | 22 + .../src/lib/i18n/messages/fr/services.json | 14 + .../src/lib/i18n/messages/fr/settings.json | 20 + .../src/lib/i18n/messages/fr/translate.json | 93 + .../i18n/messages/fr/translateComplete.json | 6 + frontend/src/lib/i18n/messages/index.json | 405 + frontend/src/lib/i18n/messages/it/admin.json | 48 + .../src/lib/i18n/messages/it/apiKeys.json | 72 + frontend/src/lib/i18n/messages/it/auth.json | 3 + .../src/lib/i18n/messages/it/checkout.json | 12 + frontend/src/lib/i18n/messages/it/common.json | 4 + .../src/lib/i18n/messages/it/context.json | 25 + .../lib/i18n/messages/it/cookieConsent.json | 7 + .../src/lib/i18n/messages/it/dashboard.json | 111 + .../lib/i18n/messages/it/fileUploader.json | 31 + .../lib/i18n/messages/it/forgotPassword.json | 14 + .../src/lib/i18n/messages/it/glossaries.json | 189 + frontend/src/lib/i18n/messages/it/index.ts | 60 + .../src/lib/i18n/messages/it/landing.json | 146 + .../lib/i18n/messages/it/langSelector.json | 7 + frontend/src/lib/i18n/messages/it/layout.json | 5 + frontend/src/lib/i18n/messages/it/login.json | 18 + .../src/lib/i18n/messages/it/memento.json | 6 + .../src/lib/i18n/messages/it/pricing.json | 151 + .../src/lib/i18n/messages/it/profile.json | 58 + .../i18n/messages/it/providerSelector.json | 7 + .../lib/i18n/messages/it/providerTheme.json | 29 + .../src/lib/i18n/messages/it/register.json | 29 + .../lib/i18n/messages/it/resetPassword.json | 22 + .../src/lib/i18n/messages/it/services.json | 14 + .../src/lib/i18n/messages/it/settings.json | 20 + .../src/lib/i18n/messages/it/translate.json | 92 + .../i18n/messages/it/translateComplete.json | 6 + frontend/src/lib/i18n/messages/ja/admin.json | 48 + .../src/lib/i18n/messages/ja/apiKeys.json | 72 + frontend/src/lib/i18n/messages/ja/auth.json | 3 + .../src/lib/i18n/messages/ja/checkout.json | 12 + frontend/src/lib/i18n/messages/ja/common.json | 4 + .../src/lib/i18n/messages/ja/context.json | 25 + .../lib/i18n/messages/ja/cookieConsent.json | 7 + .../src/lib/i18n/messages/ja/dashboard.json | 111 + .../lib/i18n/messages/ja/fileUploader.json | 31 + .../lib/i18n/messages/ja/forgotPassword.json | 14 + .../src/lib/i18n/messages/ja/glossaries.json | 189 + frontend/src/lib/i18n/messages/ja/index.ts | 60 + .../src/lib/i18n/messages/ja/landing.json | 146 + .../lib/i18n/messages/ja/langSelector.json | 7 + frontend/src/lib/i18n/messages/ja/layout.json | 5 + frontend/src/lib/i18n/messages/ja/login.json | 16 + .../src/lib/i18n/messages/ja/memento.json | 6 + .../src/lib/i18n/messages/ja/pricing.json | 151 + .../src/lib/i18n/messages/ja/profile.json | 58 + .../i18n/messages/ja/providerSelector.json | 7 + .../lib/i18n/messages/ja/providerTheme.json | 29 + .../src/lib/i18n/messages/ja/register.json | 29 + .../lib/i18n/messages/ja/resetPassword.json | 22 + .../src/lib/i18n/messages/ja/services.json | 14 + .../src/lib/i18n/messages/ja/settings.json | 20 + .../src/lib/i18n/messages/ja/translate.json | 92 + .../i18n/messages/ja/translateComplete.json | 6 + frontend/src/lib/i18n/messages/ko/admin.json | 48 + .../src/lib/i18n/messages/ko/apiKeys.json | 72 + frontend/src/lib/i18n/messages/ko/auth.json | 3 + .../src/lib/i18n/messages/ko/checkout.json | 12 + frontend/src/lib/i18n/messages/ko/common.json | 4 + .../src/lib/i18n/messages/ko/context.json | 25 + .../lib/i18n/messages/ko/cookieConsent.json | 7 + .../src/lib/i18n/messages/ko/dashboard.json | 111 + .../lib/i18n/messages/ko/fileUploader.json | 31 + .../lib/i18n/messages/ko/forgotPassword.json | 14 + .../src/lib/i18n/messages/ko/glossaries.json | 189 + frontend/src/lib/i18n/messages/ko/index.ts | 60 + .../src/lib/i18n/messages/ko/landing.json | 146 + .../lib/i18n/messages/ko/langSelector.json | 7 + frontend/src/lib/i18n/messages/ko/layout.json | 5 + frontend/src/lib/i18n/messages/ko/login.json | 16 + .../src/lib/i18n/messages/ko/memento.json | 6 + .../src/lib/i18n/messages/ko/pricing.json | 151 + .../src/lib/i18n/messages/ko/profile.json | 58 + .../i18n/messages/ko/providerSelector.json | 7 + .../lib/i18n/messages/ko/providerTheme.json | 29 + .../src/lib/i18n/messages/ko/register.json | 29 + .../lib/i18n/messages/ko/resetPassword.json | 22 + .../src/lib/i18n/messages/ko/services.json | 14 + .../src/lib/i18n/messages/ko/settings.json | 20 + .../src/lib/i18n/messages/ko/translate.json | 92 + .../i18n/messages/ko/translateComplete.json | 6 + frontend/src/lib/i18n/messages/nl/admin.json | 48 + .../src/lib/i18n/messages/nl/apiKeys.json | 72 + frontend/src/lib/i18n/messages/nl/auth.json | 3 + .../src/lib/i18n/messages/nl/checkout.json | 12 + frontend/src/lib/i18n/messages/nl/common.json | 4 + .../src/lib/i18n/messages/nl/context.json | 25 + .../lib/i18n/messages/nl/cookieConsent.json | 7 + .../src/lib/i18n/messages/nl/dashboard.json | 111 + .../lib/i18n/messages/nl/fileUploader.json | 31 + .../lib/i18n/messages/nl/forgotPassword.json | 14 + .../src/lib/i18n/messages/nl/glossaries.json | 189 + frontend/src/lib/i18n/messages/nl/index.ts | 60 + .../src/lib/i18n/messages/nl/landing.json | 146 + .../lib/i18n/messages/nl/langSelector.json | 7 + frontend/src/lib/i18n/messages/nl/layout.json | 5 + frontend/src/lib/i18n/messages/nl/login.json | 18 + .../src/lib/i18n/messages/nl/memento.json | 6 + .../src/lib/i18n/messages/nl/pricing.json | 151 + .../src/lib/i18n/messages/nl/profile.json | 58 + .../i18n/messages/nl/providerSelector.json | 7 + .../lib/i18n/messages/nl/providerTheme.json | 29 + .../src/lib/i18n/messages/nl/register.json | 29 + .../lib/i18n/messages/nl/resetPassword.json | 22 + .../src/lib/i18n/messages/nl/services.json | 14 + .../src/lib/i18n/messages/nl/settings.json | 20 + .../src/lib/i18n/messages/nl/translate.json | 92 + .../i18n/messages/nl/translateComplete.json | 6 + frontend/src/lib/i18n/messages/pt/admin.json | 48 + .../src/lib/i18n/messages/pt/apiKeys.json | 72 + frontend/src/lib/i18n/messages/pt/auth.json | 3 + .../src/lib/i18n/messages/pt/checkout.json | 12 + frontend/src/lib/i18n/messages/pt/common.json | 4 + .../src/lib/i18n/messages/pt/context.json | 25 + .../lib/i18n/messages/pt/cookieConsent.json | 7 + .../src/lib/i18n/messages/pt/dashboard.json | 111 + .../lib/i18n/messages/pt/fileUploader.json | 31 + .../lib/i18n/messages/pt/forgotPassword.json | 14 + .../src/lib/i18n/messages/pt/glossaries.json | 189 + frontend/src/lib/i18n/messages/pt/index.ts | 60 + .../src/lib/i18n/messages/pt/landing.json | 146 + .../lib/i18n/messages/pt/langSelector.json | 7 + frontend/src/lib/i18n/messages/pt/layout.json | 5 + frontend/src/lib/i18n/messages/pt/login.json | 18 + .../src/lib/i18n/messages/pt/memento.json | 6 + .../src/lib/i18n/messages/pt/pricing.json | 151 + .../src/lib/i18n/messages/pt/profile.json | 58 + .../i18n/messages/pt/providerSelector.json | 7 + .../lib/i18n/messages/pt/providerTheme.json | 29 + .../src/lib/i18n/messages/pt/register.json | 29 + .../lib/i18n/messages/pt/resetPassword.json | 22 + .../src/lib/i18n/messages/pt/services.json | 14 + .../src/lib/i18n/messages/pt/settings.json | 20 + .../src/lib/i18n/messages/pt/translate.json | 92 + .../i18n/messages/pt/translateComplete.json | 6 + frontend/src/lib/i18n/messages/ru/admin.json | 48 + .../src/lib/i18n/messages/ru/apiKeys.json | 72 + frontend/src/lib/i18n/messages/ru/auth.json | 3 + .../src/lib/i18n/messages/ru/checkout.json | 12 + frontend/src/lib/i18n/messages/ru/common.json | 4 + .../src/lib/i18n/messages/ru/context.json | 25 + .../lib/i18n/messages/ru/cookieConsent.json | 7 + .../src/lib/i18n/messages/ru/dashboard.json | 111 + .../lib/i18n/messages/ru/fileUploader.json | 31 + .../lib/i18n/messages/ru/forgotPassword.json | 14 + .../src/lib/i18n/messages/ru/glossaries.json | 189 + frontend/src/lib/i18n/messages/ru/index.ts | 60 + .../src/lib/i18n/messages/ru/landing.json | 146 + .../lib/i18n/messages/ru/langSelector.json | 7 + frontend/src/lib/i18n/messages/ru/layout.json | 5 + frontend/src/lib/i18n/messages/ru/login.json | 18 + .../src/lib/i18n/messages/ru/memento.json | 6 + .../src/lib/i18n/messages/ru/pricing.json | 151 + .../src/lib/i18n/messages/ru/profile.json | 58 + .../i18n/messages/ru/providerSelector.json | 7 + .../lib/i18n/messages/ru/providerTheme.json | 29 + .../src/lib/i18n/messages/ru/register.json | 29 + .../lib/i18n/messages/ru/resetPassword.json | 22 + .../src/lib/i18n/messages/ru/services.json | 14 + .../src/lib/i18n/messages/ru/settings.json | 20 + .../src/lib/i18n/messages/ru/translate.json | 92 + .../i18n/messages/ru/translateComplete.json | 6 + frontend/src/lib/i18n/messages/zh/admin.json | 48 + .../src/lib/i18n/messages/zh/apiKeys.json | 72 + frontend/src/lib/i18n/messages/zh/auth.json | 3 + .../src/lib/i18n/messages/zh/checkout.json | 12 + frontend/src/lib/i18n/messages/zh/common.json | 4 + .../src/lib/i18n/messages/zh/context.json | 25 + .../lib/i18n/messages/zh/cookieConsent.json | 7 + .../src/lib/i18n/messages/zh/dashboard.json | 111 + .../lib/i18n/messages/zh/fileUploader.json | 31 + .../src/lib/i18n/messages/zh/glossaries.json | 189 + frontend/src/lib/i18n/messages/zh/index.ts | 56 + .../src/lib/i18n/messages/zh/landing.json | 146 + .../lib/i18n/messages/zh/langSelector.json | 7 + frontend/src/lib/i18n/messages/zh/layout.json | 5 + frontend/src/lib/i18n/messages/zh/login.json | 6 + .../src/lib/i18n/messages/zh/memento.json | 6 + .../src/lib/i18n/messages/zh/pricing.json | 151 + .../src/lib/i18n/messages/zh/profile.json | 58 + .../i18n/messages/zh/providerSelector.json | 7 + .../lib/i18n/messages/zh/providerTheme.json | 29 + .../src/lib/i18n/messages/zh/register.json | 29 + .../src/lib/i18n/messages/zh/services.json | 14 + .../src/lib/i18n/messages/zh/settings.json | 20 + .../src/lib/i18n/messages/zh/translate.json | 92 + .../i18n/messages/zh/translateComplete.json | 6 + frontend/src/messages/en.json | 394 - frontend/src/messages/fr.json | 394 - pyproject.toml | 20 +- pytest.ini | 2 + routes/legacy_routes.py | 55 - scripts/analyze_i18n.py | 20 + scripts/generate_i18n_index.py | 39 + scripts/split_i18n.py | 107 + services/translation_service.py | 49 +- tests/test_story_3_5_api_versioning.py | 4 +- tests/test_translation_service.py | 40 + 365 files changed, 23910 insertions(+), 14955 deletions(-) create mode 100644 frontend/pnpm-lock.yaml create mode 100644 frontend/src/lib/i18n/messages/ar/admin.json create mode 100644 frontend/src/lib/i18n/messages/ar/apiKeys.json create mode 100644 frontend/src/lib/i18n/messages/ar/auth.json create mode 100644 frontend/src/lib/i18n/messages/ar/checkout.json create mode 100644 frontend/src/lib/i18n/messages/ar/common.json create mode 100644 frontend/src/lib/i18n/messages/ar/context.json create mode 100644 frontend/src/lib/i18n/messages/ar/cookieConsent.json create mode 100644 frontend/src/lib/i18n/messages/ar/dashboard.json create mode 100644 frontend/src/lib/i18n/messages/ar/fileUploader.json create mode 100644 frontend/src/lib/i18n/messages/ar/glossaries.json create mode 100644 frontend/src/lib/i18n/messages/ar/index.ts create mode 100644 frontend/src/lib/i18n/messages/ar/landing.json create mode 100644 frontend/src/lib/i18n/messages/ar/langSelector.json create mode 100644 frontend/src/lib/i18n/messages/ar/layout.json create mode 100644 frontend/src/lib/i18n/messages/ar/login.json create mode 100644 frontend/src/lib/i18n/messages/ar/memento.json create mode 100644 frontend/src/lib/i18n/messages/ar/pricing.json create mode 100644 frontend/src/lib/i18n/messages/ar/profile.json create mode 100644 frontend/src/lib/i18n/messages/ar/providerSelector.json create mode 100644 frontend/src/lib/i18n/messages/ar/providerTheme.json create mode 100644 frontend/src/lib/i18n/messages/ar/register.json create mode 100644 frontend/src/lib/i18n/messages/ar/services.json create mode 100644 frontend/src/lib/i18n/messages/ar/settings.json create mode 100644 frontend/src/lib/i18n/messages/ar/translate.json create mode 100644 frontend/src/lib/i18n/messages/ar/translateComplete.json create mode 100644 frontend/src/lib/i18n/messages/de/admin.json create mode 100644 frontend/src/lib/i18n/messages/de/apiKeys.json create mode 100644 frontend/src/lib/i18n/messages/de/auth.json create mode 100644 frontend/src/lib/i18n/messages/de/checkout.json create mode 100644 frontend/src/lib/i18n/messages/de/common.json create mode 100644 frontend/src/lib/i18n/messages/de/context.json create mode 100644 frontend/src/lib/i18n/messages/de/cookieConsent.json create mode 100644 frontend/src/lib/i18n/messages/de/dashboard.json create mode 100644 frontend/src/lib/i18n/messages/de/fileUploader.json create mode 100644 frontend/src/lib/i18n/messages/de/forgotPassword.json create mode 100644 frontend/src/lib/i18n/messages/de/glossaries.json create mode 100644 frontend/src/lib/i18n/messages/de/index.ts create mode 100644 frontend/src/lib/i18n/messages/de/landing.json create mode 100644 frontend/src/lib/i18n/messages/de/langSelector.json create mode 100644 frontend/src/lib/i18n/messages/de/layout.json create mode 100644 frontend/src/lib/i18n/messages/de/login.json create mode 100644 frontend/src/lib/i18n/messages/de/memento.json create mode 100644 frontend/src/lib/i18n/messages/de/pricing.json create mode 100644 frontend/src/lib/i18n/messages/de/profile.json create mode 100644 frontend/src/lib/i18n/messages/de/providerSelector.json create mode 100644 frontend/src/lib/i18n/messages/de/providerTheme.json create mode 100644 frontend/src/lib/i18n/messages/de/register.json create mode 100644 frontend/src/lib/i18n/messages/de/resetPassword.json create mode 100644 frontend/src/lib/i18n/messages/de/services.json create mode 100644 frontend/src/lib/i18n/messages/de/settings.json create mode 100644 frontend/src/lib/i18n/messages/de/translate.json create mode 100644 frontend/src/lib/i18n/messages/de/translateComplete.json create mode 100644 frontend/src/lib/i18n/messages/en/admin.json create mode 100644 frontend/src/lib/i18n/messages/en/apiKeys.json create mode 100644 frontend/src/lib/i18n/messages/en/auth.json create mode 100644 frontend/src/lib/i18n/messages/en/checkout.json create mode 100644 frontend/src/lib/i18n/messages/en/common.json create mode 100644 frontend/src/lib/i18n/messages/en/context.json create mode 100644 frontend/src/lib/i18n/messages/en/cookieConsent.json create mode 100644 frontend/src/lib/i18n/messages/en/dashboard.json create mode 100644 frontend/src/lib/i18n/messages/en/fileUploader.json create mode 100644 frontend/src/lib/i18n/messages/en/forgotPassword.json create mode 100644 frontend/src/lib/i18n/messages/en/glossaries.json create mode 100644 frontend/src/lib/i18n/messages/en/index.ts create mode 100644 frontend/src/lib/i18n/messages/en/landing.json create mode 100644 frontend/src/lib/i18n/messages/en/langSelector.json create mode 100644 frontend/src/lib/i18n/messages/en/layout.json create mode 100644 frontend/src/lib/i18n/messages/en/login.json create mode 100644 frontend/src/lib/i18n/messages/en/memento.json create mode 100644 frontend/src/lib/i18n/messages/en/pricing.json create mode 100644 frontend/src/lib/i18n/messages/en/profile.json create mode 100644 frontend/src/lib/i18n/messages/en/providerSelector.json create mode 100644 frontend/src/lib/i18n/messages/en/providerTheme.json create mode 100644 frontend/src/lib/i18n/messages/en/register.json create mode 100644 frontend/src/lib/i18n/messages/en/resetPassword.json create mode 100644 frontend/src/lib/i18n/messages/en/services.json create mode 100644 frontend/src/lib/i18n/messages/en/settings.json create mode 100644 frontend/src/lib/i18n/messages/en/translate.json create mode 100644 frontend/src/lib/i18n/messages/en/translateComplete.json create mode 100644 frontend/src/lib/i18n/messages/es/admin.json create mode 100644 frontend/src/lib/i18n/messages/es/apiKeys.json create mode 100644 frontend/src/lib/i18n/messages/es/auth.json create mode 100644 frontend/src/lib/i18n/messages/es/checkout.json create mode 100644 frontend/src/lib/i18n/messages/es/common.json create mode 100644 frontend/src/lib/i18n/messages/es/context.json create mode 100644 frontend/src/lib/i18n/messages/es/cookieConsent.json create mode 100644 frontend/src/lib/i18n/messages/es/dashboard.json create mode 100644 frontend/src/lib/i18n/messages/es/fileUploader.json create mode 100644 frontend/src/lib/i18n/messages/es/forgotPassword.json create mode 100644 frontend/src/lib/i18n/messages/es/glossaries.json create mode 100644 frontend/src/lib/i18n/messages/es/index.ts create mode 100644 frontend/src/lib/i18n/messages/es/landing.json create mode 100644 frontend/src/lib/i18n/messages/es/langSelector.json create mode 100644 frontend/src/lib/i18n/messages/es/layout.json create mode 100644 frontend/src/lib/i18n/messages/es/login.json create mode 100644 frontend/src/lib/i18n/messages/es/memento.json create mode 100644 frontend/src/lib/i18n/messages/es/pricing.json create mode 100644 frontend/src/lib/i18n/messages/es/profile.json create mode 100644 frontend/src/lib/i18n/messages/es/providerSelector.json create mode 100644 frontend/src/lib/i18n/messages/es/providerTheme.json create mode 100644 frontend/src/lib/i18n/messages/es/register.json create mode 100644 frontend/src/lib/i18n/messages/es/resetPassword.json create mode 100644 frontend/src/lib/i18n/messages/es/services.json create mode 100644 frontend/src/lib/i18n/messages/es/settings.json create mode 100644 frontend/src/lib/i18n/messages/es/translate.json create mode 100644 frontend/src/lib/i18n/messages/es/translateComplete.json create mode 100644 frontend/src/lib/i18n/messages/fa/admin.json create mode 100644 frontend/src/lib/i18n/messages/fa/apiKeys.json create mode 100644 frontend/src/lib/i18n/messages/fa/auth.json create mode 100644 frontend/src/lib/i18n/messages/fa/checkout.json create mode 100644 frontend/src/lib/i18n/messages/fa/common.json create mode 100644 frontend/src/lib/i18n/messages/fa/context.json create mode 100644 frontend/src/lib/i18n/messages/fa/cookieConsent.json create mode 100644 frontend/src/lib/i18n/messages/fa/dashboard.json create mode 100644 frontend/src/lib/i18n/messages/fa/fileUploader.json create mode 100644 frontend/src/lib/i18n/messages/fa/glossaries.json create mode 100644 frontend/src/lib/i18n/messages/fa/index.ts create mode 100644 frontend/src/lib/i18n/messages/fa/landing.json create mode 100644 frontend/src/lib/i18n/messages/fa/langSelector.json create mode 100644 frontend/src/lib/i18n/messages/fa/layout.json create mode 100644 frontend/src/lib/i18n/messages/fa/login.json create mode 100644 frontend/src/lib/i18n/messages/fa/memento.json create mode 100644 frontend/src/lib/i18n/messages/fa/pricing.json create mode 100644 frontend/src/lib/i18n/messages/fa/profile.json create mode 100644 frontend/src/lib/i18n/messages/fa/providerSelector.json create mode 100644 frontend/src/lib/i18n/messages/fa/providerTheme.json create mode 100644 frontend/src/lib/i18n/messages/fa/register.json create mode 100644 frontend/src/lib/i18n/messages/fa/services.json create mode 100644 frontend/src/lib/i18n/messages/fa/settings.json create mode 100644 frontend/src/lib/i18n/messages/fa/translate.json create mode 100644 frontend/src/lib/i18n/messages/fa/translateComplete.json create mode 100644 frontend/src/lib/i18n/messages/fr/admin.json create mode 100644 frontend/src/lib/i18n/messages/fr/apiKeys.json create mode 100644 frontend/src/lib/i18n/messages/fr/auth.json create mode 100644 frontend/src/lib/i18n/messages/fr/checkout.json create mode 100644 frontend/src/lib/i18n/messages/fr/common.json create mode 100644 frontend/src/lib/i18n/messages/fr/context.json create mode 100644 frontend/src/lib/i18n/messages/fr/cookieConsent.json create mode 100644 frontend/src/lib/i18n/messages/fr/dashboard.json create mode 100644 frontend/src/lib/i18n/messages/fr/fileUploader.json create mode 100644 frontend/src/lib/i18n/messages/fr/forgotPassword.json create mode 100644 frontend/src/lib/i18n/messages/fr/glossaries.json create mode 100644 frontend/src/lib/i18n/messages/fr/index.ts create mode 100644 frontend/src/lib/i18n/messages/fr/landing.json create mode 100644 frontend/src/lib/i18n/messages/fr/langSelector.json create mode 100644 frontend/src/lib/i18n/messages/fr/layout.json create mode 100644 frontend/src/lib/i18n/messages/fr/login.json create mode 100644 frontend/src/lib/i18n/messages/fr/memento.json create mode 100644 frontend/src/lib/i18n/messages/fr/pricing.json create mode 100644 frontend/src/lib/i18n/messages/fr/profile.json create mode 100644 frontend/src/lib/i18n/messages/fr/providerSelector.json create mode 100644 frontend/src/lib/i18n/messages/fr/providerTheme.json create mode 100644 frontend/src/lib/i18n/messages/fr/register.json create mode 100644 frontend/src/lib/i18n/messages/fr/resetPassword.json create mode 100644 frontend/src/lib/i18n/messages/fr/services.json create mode 100644 frontend/src/lib/i18n/messages/fr/settings.json create mode 100644 frontend/src/lib/i18n/messages/fr/translate.json create mode 100644 frontend/src/lib/i18n/messages/fr/translateComplete.json create mode 100644 frontend/src/lib/i18n/messages/index.json create mode 100644 frontend/src/lib/i18n/messages/it/admin.json create mode 100644 frontend/src/lib/i18n/messages/it/apiKeys.json create mode 100644 frontend/src/lib/i18n/messages/it/auth.json create mode 100644 frontend/src/lib/i18n/messages/it/checkout.json create mode 100644 frontend/src/lib/i18n/messages/it/common.json create mode 100644 frontend/src/lib/i18n/messages/it/context.json create mode 100644 frontend/src/lib/i18n/messages/it/cookieConsent.json create mode 100644 frontend/src/lib/i18n/messages/it/dashboard.json create mode 100644 frontend/src/lib/i18n/messages/it/fileUploader.json create mode 100644 frontend/src/lib/i18n/messages/it/forgotPassword.json create mode 100644 frontend/src/lib/i18n/messages/it/glossaries.json create mode 100644 frontend/src/lib/i18n/messages/it/index.ts create mode 100644 frontend/src/lib/i18n/messages/it/landing.json create mode 100644 frontend/src/lib/i18n/messages/it/langSelector.json create mode 100644 frontend/src/lib/i18n/messages/it/layout.json create mode 100644 frontend/src/lib/i18n/messages/it/login.json create mode 100644 frontend/src/lib/i18n/messages/it/memento.json create mode 100644 frontend/src/lib/i18n/messages/it/pricing.json create mode 100644 frontend/src/lib/i18n/messages/it/profile.json create mode 100644 frontend/src/lib/i18n/messages/it/providerSelector.json create mode 100644 frontend/src/lib/i18n/messages/it/providerTheme.json create mode 100644 frontend/src/lib/i18n/messages/it/register.json create mode 100644 frontend/src/lib/i18n/messages/it/resetPassword.json create mode 100644 frontend/src/lib/i18n/messages/it/services.json create mode 100644 frontend/src/lib/i18n/messages/it/settings.json create mode 100644 frontend/src/lib/i18n/messages/it/translate.json create mode 100644 frontend/src/lib/i18n/messages/it/translateComplete.json create mode 100644 frontend/src/lib/i18n/messages/ja/admin.json create mode 100644 frontend/src/lib/i18n/messages/ja/apiKeys.json create mode 100644 frontend/src/lib/i18n/messages/ja/auth.json create mode 100644 frontend/src/lib/i18n/messages/ja/checkout.json create mode 100644 frontend/src/lib/i18n/messages/ja/common.json create mode 100644 frontend/src/lib/i18n/messages/ja/context.json create mode 100644 frontend/src/lib/i18n/messages/ja/cookieConsent.json create mode 100644 frontend/src/lib/i18n/messages/ja/dashboard.json create mode 100644 frontend/src/lib/i18n/messages/ja/fileUploader.json create mode 100644 frontend/src/lib/i18n/messages/ja/forgotPassword.json create mode 100644 frontend/src/lib/i18n/messages/ja/glossaries.json create mode 100644 frontend/src/lib/i18n/messages/ja/index.ts create mode 100644 frontend/src/lib/i18n/messages/ja/landing.json create mode 100644 frontend/src/lib/i18n/messages/ja/langSelector.json create mode 100644 frontend/src/lib/i18n/messages/ja/layout.json create mode 100644 frontend/src/lib/i18n/messages/ja/login.json create mode 100644 frontend/src/lib/i18n/messages/ja/memento.json create mode 100644 frontend/src/lib/i18n/messages/ja/pricing.json create mode 100644 frontend/src/lib/i18n/messages/ja/profile.json create mode 100644 frontend/src/lib/i18n/messages/ja/providerSelector.json create mode 100644 frontend/src/lib/i18n/messages/ja/providerTheme.json create mode 100644 frontend/src/lib/i18n/messages/ja/register.json create mode 100644 frontend/src/lib/i18n/messages/ja/resetPassword.json create mode 100644 frontend/src/lib/i18n/messages/ja/services.json create mode 100644 frontend/src/lib/i18n/messages/ja/settings.json create mode 100644 frontend/src/lib/i18n/messages/ja/translate.json create mode 100644 frontend/src/lib/i18n/messages/ja/translateComplete.json create mode 100644 frontend/src/lib/i18n/messages/ko/admin.json create mode 100644 frontend/src/lib/i18n/messages/ko/apiKeys.json create mode 100644 frontend/src/lib/i18n/messages/ko/auth.json create mode 100644 frontend/src/lib/i18n/messages/ko/checkout.json create mode 100644 frontend/src/lib/i18n/messages/ko/common.json create mode 100644 frontend/src/lib/i18n/messages/ko/context.json create mode 100644 frontend/src/lib/i18n/messages/ko/cookieConsent.json create mode 100644 frontend/src/lib/i18n/messages/ko/dashboard.json create mode 100644 frontend/src/lib/i18n/messages/ko/fileUploader.json create mode 100644 frontend/src/lib/i18n/messages/ko/forgotPassword.json create mode 100644 frontend/src/lib/i18n/messages/ko/glossaries.json create mode 100644 frontend/src/lib/i18n/messages/ko/index.ts create mode 100644 frontend/src/lib/i18n/messages/ko/landing.json create mode 100644 frontend/src/lib/i18n/messages/ko/langSelector.json create mode 100644 frontend/src/lib/i18n/messages/ko/layout.json create mode 100644 frontend/src/lib/i18n/messages/ko/login.json create mode 100644 frontend/src/lib/i18n/messages/ko/memento.json create mode 100644 frontend/src/lib/i18n/messages/ko/pricing.json create mode 100644 frontend/src/lib/i18n/messages/ko/profile.json create mode 100644 frontend/src/lib/i18n/messages/ko/providerSelector.json create mode 100644 frontend/src/lib/i18n/messages/ko/providerTheme.json create mode 100644 frontend/src/lib/i18n/messages/ko/register.json create mode 100644 frontend/src/lib/i18n/messages/ko/resetPassword.json create mode 100644 frontend/src/lib/i18n/messages/ko/services.json create mode 100644 frontend/src/lib/i18n/messages/ko/settings.json create mode 100644 frontend/src/lib/i18n/messages/ko/translate.json create mode 100644 frontend/src/lib/i18n/messages/ko/translateComplete.json create mode 100644 frontend/src/lib/i18n/messages/nl/admin.json create mode 100644 frontend/src/lib/i18n/messages/nl/apiKeys.json create mode 100644 frontend/src/lib/i18n/messages/nl/auth.json create mode 100644 frontend/src/lib/i18n/messages/nl/checkout.json create mode 100644 frontend/src/lib/i18n/messages/nl/common.json create mode 100644 frontend/src/lib/i18n/messages/nl/context.json create mode 100644 frontend/src/lib/i18n/messages/nl/cookieConsent.json create mode 100644 frontend/src/lib/i18n/messages/nl/dashboard.json create mode 100644 frontend/src/lib/i18n/messages/nl/fileUploader.json create mode 100644 frontend/src/lib/i18n/messages/nl/forgotPassword.json create mode 100644 frontend/src/lib/i18n/messages/nl/glossaries.json create mode 100644 frontend/src/lib/i18n/messages/nl/index.ts create mode 100644 frontend/src/lib/i18n/messages/nl/landing.json create mode 100644 frontend/src/lib/i18n/messages/nl/langSelector.json create mode 100644 frontend/src/lib/i18n/messages/nl/layout.json create mode 100644 frontend/src/lib/i18n/messages/nl/login.json create mode 100644 frontend/src/lib/i18n/messages/nl/memento.json create mode 100644 frontend/src/lib/i18n/messages/nl/pricing.json create mode 100644 frontend/src/lib/i18n/messages/nl/profile.json create mode 100644 frontend/src/lib/i18n/messages/nl/providerSelector.json create mode 100644 frontend/src/lib/i18n/messages/nl/providerTheme.json create mode 100644 frontend/src/lib/i18n/messages/nl/register.json create mode 100644 frontend/src/lib/i18n/messages/nl/resetPassword.json create mode 100644 frontend/src/lib/i18n/messages/nl/services.json create mode 100644 frontend/src/lib/i18n/messages/nl/settings.json create mode 100644 frontend/src/lib/i18n/messages/nl/translate.json create mode 100644 frontend/src/lib/i18n/messages/nl/translateComplete.json create mode 100644 frontend/src/lib/i18n/messages/pt/admin.json create mode 100644 frontend/src/lib/i18n/messages/pt/apiKeys.json create mode 100644 frontend/src/lib/i18n/messages/pt/auth.json create mode 100644 frontend/src/lib/i18n/messages/pt/checkout.json create mode 100644 frontend/src/lib/i18n/messages/pt/common.json create mode 100644 frontend/src/lib/i18n/messages/pt/context.json create mode 100644 frontend/src/lib/i18n/messages/pt/cookieConsent.json create mode 100644 frontend/src/lib/i18n/messages/pt/dashboard.json create mode 100644 frontend/src/lib/i18n/messages/pt/fileUploader.json create mode 100644 frontend/src/lib/i18n/messages/pt/forgotPassword.json create mode 100644 frontend/src/lib/i18n/messages/pt/glossaries.json create mode 100644 frontend/src/lib/i18n/messages/pt/index.ts create mode 100644 frontend/src/lib/i18n/messages/pt/landing.json create mode 100644 frontend/src/lib/i18n/messages/pt/langSelector.json create mode 100644 frontend/src/lib/i18n/messages/pt/layout.json create mode 100644 frontend/src/lib/i18n/messages/pt/login.json create mode 100644 frontend/src/lib/i18n/messages/pt/memento.json create mode 100644 frontend/src/lib/i18n/messages/pt/pricing.json create mode 100644 frontend/src/lib/i18n/messages/pt/profile.json create mode 100644 frontend/src/lib/i18n/messages/pt/providerSelector.json create mode 100644 frontend/src/lib/i18n/messages/pt/providerTheme.json create mode 100644 frontend/src/lib/i18n/messages/pt/register.json create mode 100644 frontend/src/lib/i18n/messages/pt/resetPassword.json create mode 100644 frontend/src/lib/i18n/messages/pt/services.json create mode 100644 frontend/src/lib/i18n/messages/pt/settings.json create mode 100644 frontend/src/lib/i18n/messages/pt/translate.json create mode 100644 frontend/src/lib/i18n/messages/pt/translateComplete.json create mode 100644 frontend/src/lib/i18n/messages/ru/admin.json create mode 100644 frontend/src/lib/i18n/messages/ru/apiKeys.json create mode 100644 frontend/src/lib/i18n/messages/ru/auth.json create mode 100644 frontend/src/lib/i18n/messages/ru/checkout.json create mode 100644 frontend/src/lib/i18n/messages/ru/common.json create mode 100644 frontend/src/lib/i18n/messages/ru/context.json create mode 100644 frontend/src/lib/i18n/messages/ru/cookieConsent.json create mode 100644 frontend/src/lib/i18n/messages/ru/dashboard.json create mode 100644 frontend/src/lib/i18n/messages/ru/fileUploader.json create mode 100644 frontend/src/lib/i18n/messages/ru/forgotPassword.json create mode 100644 frontend/src/lib/i18n/messages/ru/glossaries.json create mode 100644 frontend/src/lib/i18n/messages/ru/index.ts create mode 100644 frontend/src/lib/i18n/messages/ru/landing.json create mode 100644 frontend/src/lib/i18n/messages/ru/langSelector.json create mode 100644 frontend/src/lib/i18n/messages/ru/layout.json create mode 100644 frontend/src/lib/i18n/messages/ru/login.json create mode 100644 frontend/src/lib/i18n/messages/ru/memento.json create mode 100644 frontend/src/lib/i18n/messages/ru/pricing.json create mode 100644 frontend/src/lib/i18n/messages/ru/profile.json create mode 100644 frontend/src/lib/i18n/messages/ru/providerSelector.json create mode 100644 frontend/src/lib/i18n/messages/ru/providerTheme.json create mode 100644 frontend/src/lib/i18n/messages/ru/register.json create mode 100644 frontend/src/lib/i18n/messages/ru/resetPassword.json create mode 100644 frontend/src/lib/i18n/messages/ru/services.json create mode 100644 frontend/src/lib/i18n/messages/ru/settings.json create mode 100644 frontend/src/lib/i18n/messages/ru/translate.json create mode 100644 frontend/src/lib/i18n/messages/ru/translateComplete.json create mode 100644 frontend/src/lib/i18n/messages/zh/admin.json create mode 100644 frontend/src/lib/i18n/messages/zh/apiKeys.json create mode 100644 frontend/src/lib/i18n/messages/zh/auth.json create mode 100644 frontend/src/lib/i18n/messages/zh/checkout.json create mode 100644 frontend/src/lib/i18n/messages/zh/common.json create mode 100644 frontend/src/lib/i18n/messages/zh/context.json create mode 100644 frontend/src/lib/i18n/messages/zh/cookieConsent.json create mode 100644 frontend/src/lib/i18n/messages/zh/dashboard.json create mode 100644 frontend/src/lib/i18n/messages/zh/fileUploader.json create mode 100644 frontend/src/lib/i18n/messages/zh/glossaries.json create mode 100644 frontend/src/lib/i18n/messages/zh/index.ts create mode 100644 frontend/src/lib/i18n/messages/zh/landing.json create mode 100644 frontend/src/lib/i18n/messages/zh/langSelector.json create mode 100644 frontend/src/lib/i18n/messages/zh/layout.json create mode 100644 frontend/src/lib/i18n/messages/zh/login.json create mode 100644 frontend/src/lib/i18n/messages/zh/memento.json create mode 100644 frontend/src/lib/i18n/messages/zh/pricing.json create mode 100644 frontend/src/lib/i18n/messages/zh/profile.json create mode 100644 frontend/src/lib/i18n/messages/zh/providerSelector.json create mode 100644 frontend/src/lib/i18n/messages/zh/providerTheme.json create mode 100644 frontend/src/lib/i18n/messages/zh/register.json create mode 100644 frontend/src/lib/i18n/messages/zh/services.json create mode 100644 frontend/src/lib/i18n/messages/zh/settings.json create mode 100644 frontend/src/lib/i18n/messages/zh/translate.json create mode 100644 frontend/src/lib/i18n/messages/zh/translateComplete.json delete mode 100644 frontend/src/messages/en.json delete mode 100644 frontend/src/messages/fr.json create mode 100644 scripts/analyze_i18n.py create mode 100644 scripts/generate_i18n_index.py create mode 100644 scripts/split_i18n.py create mode 100644 tests/test_translation_service.py diff --git a/.env.example b/.env.example index 66aef2f..15143e0 100644 --- a/.env.example +++ b/.env.example @@ -183,6 +183,11 @@ STRIPE_PRICE_BUSINESS_MONTHLY=price_xxx STRIPE_PRICE_BUSINESS_YEARLY=price_xxx # ============== Monitoring ============== +# Optional. Default: admin. Grafana admin username. +GRAFANA_USER=admin +# Required when Grafana is enabled. If absent: Grafana may fail to start. Generate with: secrets.token_urlsafe(32) +GRAFANA_PASSWORD= + # Optional. Default: INFO. Log format: json or console (default from ENV/LOG_FORMAT). LOG_LEVEL=INFO LOG_FORMAT=json diff --git a/.gitignore b/.gitignore index e692070..514f5c2 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,10 @@ uv.lock *.pem *_ssl_certificate*.zip +# Coverage reports +.coverage +htmlcov/ + +# Auto-generated pnpm workspace file (placeholders) +frontend/pnpm-workspace.yaml + diff --git a/docker-compose.monitoring.yml b/docker-compose.monitoring.yml index 3261d46..35843af 100644 --- a/docker-compose.monitoring.yml +++ b/docker-compose.monitoring.yml @@ -8,7 +8,7 @@ # docker compose -f docker-compose.yml -f docker-compose.monitoring.yml up -d # # Access: -# Grafana: http://:3001 (admin / WordlyGrafana2026!) +# Grafana: http://:3001 (admin / $GRAFANA_PASSWORD) # Ou via NPM: monitoring.wordly.art -> wordly-grafana:3000 # ============================================ @@ -54,8 +54,8 @@ services: container_name: wordly-grafana restart: unless-stopped environment: - - GF_SECURITY_ADMIN_USER=admin - - GF_SECURITY_ADMIN_PASSWORD=WordlyGrafana2026! + - GF_SECURITY_ADMIN_USER=${GRAFANA_USER:-admin} + - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD} - GF_USERS_ALLOW_SIGN_UP=false - GF_SERVER_ROOT_URL=https://monitoring.wordly.art - GF_INSTALL_PLUGINS=grafana-clock-panel diff --git a/docker-compose.yml b/docker-compose.yml index 68314c1..c421468 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -87,7 +87,7 @@ services: environment: - DATABASE_URL=postgresql+asyncpg://${POSTGRES_USER:-translate}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-translate_db} - REDIS_URL=redis://redis:6379/0 - - TRANSLATION_SERVICE=${TRANSLATION_SERVICE:-ollama} + - TRANSLATION_SERVICE=${TRANSLATION_SERVICE:-google} - OLLAMA_BASE_URL=${OLLAMA_BASE_URL:-http://ollama:11434} - OLLAMA_MODEL=${OLLAMA_MODEL:-llama3} - DEEPL_API_KEY=${DEEPL_API_KEY:-} @@ -251,7 +251,7 @@ services: restart: unless-stopped environment: - GF_SECURITY_ADMIN_USER=${GRAFANA_USER:-admin} - - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD:-WordlyGrafana2026!} + - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD} - GF_USERS_ALLOW_SIGN_UP=false - GF_SERVER_ROOT_URL=https://monitoring.wordly.art - GF_INSTALL_PLUGINS=grafana-clock-panel diff --git a/frontend/next.config.ts b/frontend/next.config.ts index 6a1a600..c90353a 100644 --- a/frontend/next.config.ts +++ b/frontend/next.config.ts @@ -5,8 +5,10 @@ import type { NextConfig } from "next"; const backendUrl = (process.env.BACKEND_URL || "http://127.0.0.1:8000").replace(/\/$/, ""); const nextConfig: NextConfig = { - // Docker: standalone output for optimized production images - output: "standalone", + // Docker: standalone output for optimized production images. + // On Windows without Developer Mode / admin rights the standalone symlink + // copy can fail with EPERM. Set NEXT_OUTPUT=default to disable standalone. + output: process.env.NEXT_OUTPUT === "default" ? undefined : "standalone", // Turbopack ne résout pas le require() dynamique de lightningcss → "Module not found". // Toujours lancer avec Webpack : npm run dev ou next dev --webpack (pas "next dev" seul). serverExternalPackages: ["lightningcss", "@tailwindcss/postcss", "@tailwindcss/node"], diff --git a/frontend/package.json b/frontend/package.json index d29f86f..554ffd6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,6 +6,7 @@ "dev": "next dev --webpack", "dev:turbo": "next dev", "build": "next build --webpack", + "build:local": "cross-env NEXT_OUTPUT=default next build --webpack", "build:turbo": "next build", "start": "next start", "lint": "eslint", @@ -33,7 +34,7 @@ "agentation-mcp": "^1.2.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "framer-motion": "^12.23.24", + "framer-motion": "11.18.2", "lucide-react": "^0.555.0", "next": "16.0.6", "next-intl": "^4.8.3", @@ -54,6 +55,7 @@ "@types/react-dom": "^19", "@vitejs/plugin-react": "^5.1.4", "agentation": "^3.0.2", + "cross-env": "^10.1.0", "eslint": "^9", "eslint-config-next": "16.0.6", "jsdom": "^28.1.0", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml new file mode 100644 index 0000000..11bbe34 --- /dev/null +++ b/frontend/pnpm-lock.yaml @@ -0,0 +1,7833 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@mlc-ai/web-llm': + specifier: ^0.2.80 + version: 0.2.84 + '@radix-ui/react-avatar': + specifier: ^1.1.11 + version: 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-checkbox': + specifier: ^1.3.3 + version: 1.3.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-dialog': + specifier: ^1.1.15 + version: 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-dropdown-menu': + specifier: ^2.1.16 + version: 2.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-label': + specifier: ^2.1.8 + version: 2.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-progress': + specifier: ^1.1.8 + version: 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-scroll-area': + specifier: ^1.2.10 + version: 1.2.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-select': + specifier: ^2.2.6 + version: 2.3.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-separator': + specifier: ^1.1.8 + version: 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': + specifier: ^1.2.4 + version: 1.2.5(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-switch': + specifier: ^1.2.6 + version: 1.3.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-tabs': + specifier: ^1.1.13 + version: 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-toast': + specifier: ^1.2.15 + version: 1.2.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-tooltip': + specifier: ^1.2.8 + version: 1.2.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@react-oauth/google': + specifier: ^0.13.5 + version: 0.13.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@tanstack/react-query': + specifier: ^5.90.21 + version: 5.101.0(react@19.2.0) + agentation-mcp: + specifier: ^1.2.0 + version: 1.2.0 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + framer-motion: + specifier: 11.18.2 + version: 11.18.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + lucide-react: + specifier: ^0.555.0 + version: 0.555.0(react@19.2.0) + next: + specifier: 16.0.6 + version: 16.0.6(@babel/core@7.29.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + next-intl: + specifier: ^4.8.3 + version: 4.13.0(next@16.0.6(@babel/core@7.29.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + next-themes: + specifier: ^0.4.6 + version: 0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: + specifier: 19.2.0 + version: 19.2.0 + react-dom: + specifier: 19.2.0 + version: 19.2.0(react@19.2.0) + react-dropzone: + specifier: ^14.3.8 + version: 14.4.1(react@19.2.0) + tailwind-merge: + specifier: ^3.4.0 + version: 3.6.0 + xlsx: + specifier: ^0.18.5 + version: 0.18.5 + zustand: + specifier: ^5.0.9 + version: 5.0.14(@types/react@19.2.17)(react@19.2.0) + devDependencies: + '@tailwindcss/postcss': + specifier: ^4 + version: 4.3.1 + '@testing-library/jest-dom': + specifier: ^6.9.1 + version: 6.9.1 + '@testing-library/react': + specifier: ^16.3.2 + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@types/node': + specifier: ^20 + version: 20.19.43 + '@types/react': + specifier: ^19 + version: 19.2.17 + '@types/react-dom': + specifier: ^19 + version: 19.2.3(@types/react@19.2.17) + '@vitejs/plugin-react': + specifier: ^5.1.4 + version: 5.2.0(vite@8.0.16(@types/node@20.19.43)(jiti@2.7.0)) + agentation: + specifier: ^3.0.2 + version: 3.0.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + cross-env: + specifier: ^10.1.0 + version: 10.1.0 + eslint: + specifier: ^9 + version: 9.39.4(jiti@2.7.0) + eslint-config-next: + specifier: 16.0.6 + version: 16.0.6(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + jsdom: + specifier: ^28.1.0 + version: 28.1.0 + lightningcss: + specifier: ^1.30.2 + version: 1.32.0 + tailwindcss: + specifier: ^4 + version: 4.3.1 + tw-animate-css: + specifier: ^1.4.0 + version: 1.4.0 + typescript: + specifier: ^5 + version: 5.9.3 + vitest: + specifier: ^4.0.18 + version: 4.1.8(@types/node@20.19.43)(jsdom@28.1.0)(vite@8.0.16(@types/node@20.19.43)(jiti@2.7.0)) + +packages: + + '@acemir/cssom@0.9.31': + resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} + + '@adobe/css-tools@4.5.0': + resolution: {integrity: sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==} + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@asamuzakjp/css-color@5.1.11': + resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/dom-selector@6.8.1': + resolution: {integrity: sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==} + + '@asamuzakjp/generational-cache@1.0.1': + resolution: {integrity: sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/nwsapi@2.3.9': + resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.29.7': + resolution: {integrity: sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.29.7': + resolution: {integrity: sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + + '@bramus/specificity@2.4.2': + resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + hasBin: true + + '@csstools/color-helpers@6.0.2': + resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} + engines: {node: '>=20.19.0'} + + '@csstools/css-calc@3.2.1': + resolution: {integrity: sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-color-parser@4.1.3': + resolution: {integrity: sha512-DOgvIPkikIOixQRlD4YF31VN6fLLUTdrzhfRbis8vm0kMTgIbEPX0Ip/YX9fOeV9iywAS4sUUbTclpan7yYP8Q==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.5': + resolution: {integrity: sha512-oNjBvzLq2GPZtJphCjLqXow/cHySHSgtxvKZb7OqSZ/xHgw6NWNhfad+6AB9cLeVm6eA9d/qMll3JdEHjy6M+A==} + peerDependencies: + css-tree: ^3.2.1 + peerDependenciesMeta: + css-tree: + optional: true + + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@epic-web/invariant@1.0.0': + resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.4': + resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@exodus/bytes@1.15.1': + resolution: {integrity: sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true + + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + + '@floating-ui/react-dom@2.1.8': + resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + + '@formatjs/fast-memoize@3.1.6': + resolution: {integrity: sha512-H5aexk1Le7T9TPmscacZ+1pR6CTa2n1wq+HDVGXhH8TzUlQQpeXzZs91dRtmFHrbeNbjPFPfQujUqm7MHgVoXQ==} + + '@formatjs/icu-messageformat-parser@3.5.11': + resolution: {integrity: sha512-NVsuNsc2dUVG9+4HBJ/srScxtA/18LqGgwtop/tuN/OIBjVl6QA+0KhfZQddDD9sEh2LeVjLFPGVU3ixa3blcA==} + + '@formatjs/icu-skeleton-parser@2.1.10': + resolution: {integrity: sha512-XuSva+8ZGawk8VnD5VD6UeH8KarQ/Z022zgjHDoHmlNiAewstXuuzXc0Hk5pGFSdG+nNw5bfJKXqj1ZXHn9yUA==} + + '@formatjs/intl-localematcher@0.8.10': + resolution: {integrity: sha512-P/IC3qws3jH+1fEs+o0RIFgXKRaQlFehjS5W0FPAqdo6hgzawLl+eD0q0JjheQ3XtoOe5n8WSYfX06KQZI/QJA==} + + '@hono/node-server@1.19.14': + resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@mlc-ai/web-llm@0.2.84': + resolution: {integrity: sha512-hrOWzK4/nGNmgoRKT8pgVmZZ2oEPpbblIWQOwpqNyvK2dysHw3KVB1gNJOuRcQfKOPhucEhX1NJzXzgMDnwSCQ==} + + '@modelcontextprotocol/sdk@1.29.0': + resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + + '@napi-rs/wasm-runtime@1.1.5': + resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@next/env@16.0.6': + resolution: {integrity: sha512-PFTK/G/vM3UJwK5XDYMFOqt8QW42mmhSgdKDapOlCqBUAOfJN2dyOnASR/xUR/JRrro0pLohh/zOJ77xUQWQAg==} + + '@next/eslint-plugin-next@16.0.6': + resolution: {integrity: sha512-9INsBF3/4XL0/tON8AGsh0svnTtDMLwv3iREGWnWkewGdOnd790tguzq9rX8xwrVthPyvaBHhw1ww0GZz0jO5Q==} + + '@next/swc-darwin-arm64@16.0.6': + resolution: {integrity: sha512-AGzKiPlDiui+9JcPRHLI4V9WFTTcKukhJTfK9qu3e0tz+Y/88B7vo5yZoO7UaikplJEHORzG3QaBFQfkjhnL0Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@16.0.6': + resolution: {integrity: sha512-LlLLNrK9WCIUkq2GciWDcquXYIf7vLxX8XE49gz7EncssZGL1vlHwgmURiJsUZAvk0HM1a8qb1ABDezsjAE/jw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@16.0.6': + resolution: {integrity: sha512-r04NzmLSGGfG8EPXKVK72N5zDNnq9pa9el78LhdtqIC3zqKh74QfKHnk24DoK4PEs6eY7sIK/CnNpt30oc59kg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-arm64-musl@16.0.6': + resolution: {integrity: sha512-hfB/QV0hA7lbD1OJxp52wVDlpffUMfyxUB5ysZbb/pBC5iuhyLcEKSVQo56PFUUmUQzbMsAtUu6k2Gh9bBtWXA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@next/swc-linux-x64-gnu@16.0.6': + resolution: {integrity: sha512-PZJushBgfvKhJBy01yXMdgL+l5XKr7uSn5jhOQXQXiH3iPT2M9iG64yHpPNGIKitKrHJInwmhPVGogZBAJOCPw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-x64-musl@16.0.6': + resolution: {integrity: sha512-LqY76IojrH9yS5fyATjLzlOIOgwyzBuNRqXwVxcGfZ58DWNQSyfnLGlfF6shAEqjwlDNLh4Z+P0rnOI87Y9jEw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@next/swc-win32-arm64-msvc@16.0.6': + resolution: {integrity: sha512-eIfSNNqAkj0tqKRf0u7BVjqylJCuabSrxnpSENY3YKApqwDMeAqYPmnOwmVe6DDl3Lvkbe7cJAyP6i9hQ5PmmQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@16.0.6': + resolution: {integrity: sha512-QGs18P4OKdK9y2F3Th42+KGnwsc2iaThOe6jxQgP62kslUU4W+g6AzI6bdIn/pslhSfxjAMU5SjakfT5Fyo/xA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + + '@oxc-project/types@0.133.0': + resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + + '@parcel/watcher-android-arm64@2.5.6': + resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.6': + resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.6': + resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.6': + resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.6': + resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm-musl@2.5.6': + resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-arm64-glibc@2.5.6': + resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm64-musl@2.5.6': + resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-x64-glibc@2.5.6': + resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-x64-musl@2.5.6': + resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@parcel/watcher-win32-arm64@2.5.6': + resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.6': + resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.6': + resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.6': + resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} + engines: {node: '>= 10.0.0'} + + '@radix-ui/number@1.1.2': + resolution: {integrity: sha512-ceTwaxc4I5IOi97DgCotl3pqiyRGvffcc0oOsE2dQYaJOFIDsDt4VWG6xEbg1QePv9QWausCEIppud/tJ1wNig==} + + '@radix-ui/primitive@1.1.4': + resolution: {integrity: sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ==} + + '@radix-ui/react-arrow@1.1.9': + resolution: {integrity: sha512-yqHW5WQ/cTpU/un7dqqIKNy2iRU8BC0JB78PEzTfCCYvZu1U6W9KwObAniMk9nhSfyotKPQTYaUD/HB0f5muig==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-avatar@1.1.12': + resolution: {integrity: sha512-NQCQyWC7QrDPhjMn8hUqFeU0lUrprIgm1AyMgLbzuQJibNnatdc3SSMo3/UGFu/eUkJUU1cEcKCnyhXTQzq6tA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-checkbox@1.3.4': + resolution: {integrity: sha512-m3JmIOAX5ZzZ6VPjxEU2dbTOhoHi0nT5riwcDwe8idocsWf4a5DXJLDtZ6LfJwMBx7W+A2b7kp2TgPEKtaiF6A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.9': + resolution: {integrity: sha512-zuSVi7ziP7uQRqc+yGxsKJfNkdyHv3ZKDaHe0gzg4dRgws96TPKWIiz84tVHP4GEcEl8bC0mdt17NkcxaJHmaQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.3': + resolution: {integrity: sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.4': + resolution: {integrity: sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.16': + resolution: {integrity: sha512-l9ok83YBclEZhbjgzt76Hw733e6cvRKPNgO6GJ/IETlufXG9p+fRu2wlvpImQvR6xdJ8h7J8J2DBvsPEiEsKMw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-direction@1.1.2': + resolution: {integrity: sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.12': + resolution: {integrity: sha512-MhoruH6xEzsbvOmo4TNgMfmtvRGyDZw4MDSdf4ybMHfezjqwzv6hyd4lsMzBp8K9Sn6sGzCF62x1I7BYUECXOg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-dropdown-menu@2.1.17': + resolution: {integrity: sha512-S6b3Jm57sY5EdDyOMLkacbB0qMnKhy1RCKZCt795ZkmtUOAvojYIZ5p7dXHIh5Cyr3jCLLI5/g64V3FKLudZmw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.4': + resolution: {integrity: sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.9': + resolution: {integrity: sha512-9Se8t+Zry+1rEOL7Y6l/4ANYU/TOtAtf8O2fKdwLltcaMcm6kOqYGbzO4tMFQ0bvzO920pRAoHpFZ4W85S3keQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.2': + resolution: {integrity: sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-label@2.1.9': + resolution: {integrity: sha512-rDoTeMbCwRVcnmo7NGT9IlPo1yXmEI+xc1URP3oeewwZEV4mdTp1dYUhYbQdo4D1q2SjKVvv4N1gNY77QAQtjA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-menu@2.1.17': + resolution: {integrity: sha512-fmbNnFyf+JYCN0DhhWnEdUTDnZD1mXaPQWivdsPIb8oOSbARfD3LIQJbLCG8a8QLCwoMxiJ7GVPIFcC8Dw8v2Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.3.0': + resolution: {integrity: sha512-9PB589e1aWZbrlFUHdz6WiPCL+xLZHQFX7oibqG/6Q0SwOkxDyQX9W/cyPa+sAPPKuC8cpLCpRczE5a/1DiwVQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.11': + resolution: {integrity: sha512-UEytdjgEh2tJGgD/gZK4FUx6t1rNIlM3U0DENhSrG7I75FGm1DnaDuVUWF1pWAWUwGmn1sCJ1VGHn8LhN1aTOw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.6': + resolution: {integrity: sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.5': + resolution: {integrity: sha512-zifXeB8Y88qCYx8PLZ5oQb32KwZub+s925mMoZsBBq9KUQqWKkREubTfs6ASjRPPBe7Jt9O8OHH89+95VG+grA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-progress@1.1.9': + resolution: {integrity: sha512-+EOkvg1Zn1vI1+fRDfRSAiJ7BWfcDAo5ASMmbqrcLZ4s4USk2FGkoHgeb2X+CkUgo2zJMiyObwf1k44CrRWsyw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.12': + resolution: {integrity: sha512-FvgPt1bRmg8Xt2QpF7NUZW3dE0ZQHGm41dAdgT2J2GJPoIXz+9Em3NobAxf4fupcxhgHu03E5CRiU2MWvObXyg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-scroll-area@1.2.11': + resolution: {integrity: sha512-DS39ziOgea75U/TrXKU2/oKp0be2jrDHnzFLvahg/0iNAT1Zq16e4Uw0WXwyXvsK+mG3BRyMb7A3NRZMDuEXtQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-select@2.3.0': + resolution: {integrity: sha512-mENc7WpJvJcW8hlMpzfFcHcEhTvYS5JMBmi9HVC1Q00uhBwML086MHYUV8QQdQv6lcu0Wg8dzd1RB8AFADcG/g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-separator@1.1.9': + resolution: {integrity: sha512-gvgW+JV/Mbjj6darztTetnmElpQEzZrXpJvfj+dOxNAxiyHEAyUvEjjl4zxblvmjmKmi3jfPoy7ZdxzCuUBJSA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.5': + resolution: {integrity: sha512-rCMO3QsIVKv5JTY5CVbo2MvO77SpEqqYc8AvRE7OWqRDOIqAKjsp+DrmnY9uc8NPdxB5E2z47HTYGeE2+NTptg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-switch@1.3.0': + resolution: {integrity: sha512-GP1EZwhoZO/GGnhM1P5/2Vpm8iN8EnngyU0oezn2l78kN8tj25pyrvjIaT7azBhK615KSt+P2w39y57YV5jVkA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tabs@1.1.14': + resolution: {integrity: sha512-D5jwp9JNuwDeCw3CYD2Fz+sSHo0droQjC8u75dJHe4aWr5q6yBiXZU+hurXnKudRgEpUkD5TsI6bjHPo5ThUxA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toast@1.2.16': + resolution: {integrity: sha512-WUymDDiN2DpoGudRN1aW4wF5O3BNQjZZO/5nngPoNiEVqjyOzirvZZNO0R6dC1ifucSINVaSv8JX1aq47VGgiA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tooltip@1.2.9': + resolution: {integrity: sha512-u6F9MmTtBSLkiXNVDrtB/yPCZarM9smNswC24YYLV/M+bth6J3Gs3vlJezEoFwKZvPvxhCpUYdUnOsNG/0XOlA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.2': + resolution: {integrity: sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.3': + resolution: {integrity: sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.3': + resolution: {integrity: sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.2': + resolution: {integrity: sha512-2uVLvLjgO7NZCWw01/FdqRwmA42J0BcjPMUCA+koFEOAb+zjqIP7SiFz/7zWPrKnVmSqr76Omq2ALyCuX4dhLw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-is-hydrated@0.1.1': + resolution: {integrity: sha512-qwOiz4Tjo8CNnrOLAYUMXeZwDzXgXpvK4TKQPmWLECM9XoWvA6+0Z2/7Ag3A4ivjS4ovbLJPbskkxioFyBhr8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.2': + resolution: {integrity: sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.1.2': + resolution: {integrity: sha512-IGBQPtRFdhN6MQ8dbegVmBq1LVZluya3F1jWY+puIcQC3MHctRwTDSBWCkL/3ZcnMJLTMJ++Z+ktmvg0F89iCw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.2': + resolution: {integrity: sha512-d8a+bBY/FxikNPlgJJoaBHZX+zKVbWHYJGTLnLvveQgFSTntkGdEKv3JDtHrMS0DNYpllz2nRsTLGLKYttbpmw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.2': + resolution: {integrity: sha512-giWQp+4mxjBPt4KZ0MmyuykFNWfbDxKt4x+fPkRYmgRFJSbCZFzUglvMb/Kjn38tm10YP4ufiQZDx3zna4LU6w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.2.5': + resolution: {integrity: sha512-tPcHNI3FajdDBFpl/Ez1m2WL0ufJqBKyHxMDBvKitopamK36WwBGOMicuMEZKkM5Wce41QxUyv6BsiqfrWBiGg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.2': + resolution: {integrity: sha512-xnXE7wG13PI+cxieVssYXlQJuYVRhH9NBoxt3KNwzghDIA69GMm7d4wXRouHIYjE+KvS6U/MsMO73NdS2MH9ZA==} + + '@react-oauth/google@0.13.5': + resolution: {integrity: sha512-xQWri2s/3nNekZJ4uuov2aAfQYu83bN3864KcFqw2pK1nNbFurQIjPFDXhWaKH3IjYJ2r/9yyIIpsn5lMqrheQ==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@rolldown/binding-android-arm64@1.0.3': + resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.3': + resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.3': + resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.3': + resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.3': + resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.3': + resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.3': + resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.3': + resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.3': + resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.3': + resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-rc.3': + resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@schummar/icu-type-parser@1.21.5': + resolution: {integrity: sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@swc/core-darwin-arm64@1.15.41': + resolution: {integrity: sha512-kREh6J5paQFvP3i7f/4FbqRNOJREutVFVOkder4GVyCBQ39YmER55cW/y1NNjwrchzFqgYswFn0mMDCqbqKzrw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.15.41': + resolution: {integrity: sha512-N8B56ESFazZAWZyIkecADSPCwlLEinW7QLMEeotCpv4J7VXwfH+OLkmRL8o96UZ+1355fwHxDTS6/wK7yucvkA==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.15.41': + resolution: {integrity: sha512-6XrId2fyle0mS5xxON8rU84mPd2Cq1kDJRj+4BnQKTd7u+2kSA6Ww+JkOP0iTNqOqt9OXhPOEAjBHAuonWcdCg==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.15.41': + resolution: {integrity: sha512-ynLIarxlkVnqHn1D0fKOVht6mNU5ks6lrH+MY3kkS+XFaGGgDxFZVjWKJlkYTKm3RCvBTfA8Ng5fLufXheMRKQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-arm64-musl@1.15.41': + resolution: {integrity: sha512-dXu/5vd4gh8symyhRF+4G7gOPkjmb4pONhh7sl+6GSiW0LOKZlfu5kXmyFbTz9smOT7jgr002qY9b1nujjXt2A==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@swc/core-linux-ppc64-gnu@1.15.41': + resolution: {integrity: sha512-XGO6zVPXoPE0gf/XnI4jBbafNT13AYgoh6ns0JCSdOetI/kqVf0vhpz7NuNgAzZrMVCsmieqjPoTwViDgh4mOQ==} + engines: {node: '>=10'} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-s390x-gnu@1.15.41': + resolution: {integrity: sha512-0WUglRwyZtW+iMi7J3iFdrCxreZZIKf4egTwEQfIYRsqFax69A0OrFj+NIoFSE03xBT/IFRrg+S8K6f9Ky+4hA==} + engines: {node: '>=10'} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@swc/core-linux-x64-gnu@1.15.41': + resolution: {integrity: sha512-VxkuQK59c0tHm6uJZCUrS3cyA2JhGGfdU6e41SZz0x/JS+4Sm7C1mIc97In14vkZJopEt7yXA2TouCqZDSygEA==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@swc/core-linux-x64-musl@1.15.41': + resolution: {integrity: sha512-/0qXIu1ZxggLuovLb22vFfKHq2AA4n6Whw5UwmVCHk4pkw7KWnPIQpMCEqUMPsNkFJig7PPp/TSYFu8ZEb2rtQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@swc/core-win32-arm64-msvc@1.15.41': + resolution: {integrity: sha512-Y481sMNZM6rECh9VO4+y26N1lWEDAyxnBZskUf37fl90uHE946VHfmiVQWT0uMFOhyJJFovGTRuF4W82dwewUg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.15.41': + resolution: {integrity: sha512-BAchBD5qeUzy3hiPSLJtaaoSm4blCLyYffOF1bGE4ETcV+OisqjUAwDQMJj++4bTpvMCDzwC+Bj3PmQyBCtscw==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.15.41': + resolution: {integrity: sha512-WOkA+fJ/ViVBQDsSV9JC52NACTe5PhlurA6viASDZGb7HR3KS01ZG7RZ+Bg6SVQFIoq3gSbTsskQVe6EbHFAYw==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.15.41': + resolution: {integrity: sha512-03nQq/082QRJJiOvp3FGbgxTGyyxMxohPTjhk/W9bD2J0tk4ukITI7goOhOO2WbaHn/lsPmo/zf8+DIXhwpgYQ==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '>=0.5.17' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@swc/types@0.1.26': + resolution: {integrity: sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==} + + '@tailwindcss/node@4.3.1': + resolution: {integrity: sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==} + + '@tailwindcss/oxide-android-arm64@4.3.1': + resolution: {integrity: sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.1': + resolution: {integrity: sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.1': + resolution: {integrity: sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.1': + resolution: {integrity: sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1': + resolution: {integrity: sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.1': + resolution: {integrity: sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.1': + resolution: {integrity: sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.1': + resolution: {integrity: sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.3.1': + resolution: {integrity: sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.3.1': + resolution: {integrity: sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.1': + resolution: {integrity: sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.1': + resolution: {integrity: sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.1': + resolution: {integrity: sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==} + engines: {node: '>= 20'} + + '@tailwindcss/postcss@4.3.1': + resolution: {integrity: sha512-dNJuNbdEJT/SWRuXTYP1WSamelsz3ztkUsdtWQPjrexysrTpaEPM40P/71knXiXLYEojqPOEGitVLLpPMS5T6A==} + + '@tanstack/query-core@5.101.0': + resolution: {integrity: sha512-cQetA74EB+seWySv1TTKr828TnP0u39m6LykwDXIo84SNortpDkp30TMEjkqtYCNP9c40uT/iwl6MLiufEt0Ow==} + + '@tanstack/react-query@5.101.0': + resolution: {integrity: sha512-rLlJXSpkqfizLWgkR5+eLeIk0MvTx/meEIR7LRjxic+qxiQP8zVjq7BqQkiCMNLQBlLfuOLqqr6KO5GtrDlmSg==} + peerDependencies: + react: ^18 || ^19 + + '@testing-library/dom@10.4.1': + resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} + engines: {node: '>=18'} + + '@testing-library/jest-dom@6.9.1': + resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + + '@testing-library/react@16.3.2': + resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} + engines: {node: '>=18'} + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/node@20.19.43': + resolution: {integrity: sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.17': + resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==} + + '@typescript-eslint/eslint-plugin@8.61.0': + resolution: {integrity: sha512-bFNvl9ZczlVb+wR2Akszf3gHfKVj/8WanXaGJ3UstTA7brNKg0cNdk6X1Psu5V7MZ2oQtzZKOEzIUehaoxbDGw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.61.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/parser@8.61.0': + resolution: {integrity: sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.61.0': + resolution: {integrity: sha512-DV42F7MLJO6Rax7SK1yg43tcnEfGUrurSpSxKuVX+a3RCTzBlH3fuxprrOJXKCJGAaw82xXocikJ0uQaqwXgGA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.61.0': + resolution: {integrity: sha512-IWdXFHFSb6mlC3HPc7QsLDm5zYEbUla6trDEHf32D3/dnuUyXd87plScSNXSbm0/RxMvObpI17sv/EDTGrGZkA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.61.0': + resolution: {integrity: sha512-O5Amvdv9ztMpxpf+vmFULGG78IE6Qwdr3bCGvqwG4nwc9H2qXkOYJJnRbRHyMkQTjv1d03olqwwwzHLMqpFePQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/type-utils@8.61.0': + resolution: {integrity: sha512-TuBiQYIkd97yBfInHCTKVYMbX4kvEmpOEuixIuzCU9p8BGT1SfyyO0d0IfDMbPIHcjn/hWnusUX5e8v5Xg+X8A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.61.0': + resolution: {integrity: sha512-9QTQpZ5Iin4CdIodfbDQFSeiSJKidgYJYug1P9CC2xWgUTvlmixViqDZNciMjwLBZyJnG4tGmPl97rVAFb1AJg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.61.0': + resolution: {integrity: sha512-42zatd5qSvvcV1JdDBCLxYRznvP4eIHpPoZXdkPFnAmanA4FuZ5dibSnCBggY8hQnqajPpoGjXFdZ7fIJKQnlA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@8.61.0': + resolution: {integrity: sha512-3bzFt7ImFMW/jVYwJamDoe/dMOdFLSC6pom6rRjdh4SZJEYupyMzem8e7vKZLclLfpHjlwSAXOUxtKxGXUiLqA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.61.0': + resolution: {integrity: sha512-QVLZu3ZPQEE+HICQyAMZ2yLQhxf0meY/wx6Hx14YcTNj13JB3qHlX3lJ02L3fLGHgERRH71kvYDwiXIguT3AjQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + resolution: {integrity: sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.12.2': + resolution: {integrity: sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + resolution: {integrity: sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.12.2': + resolution: {integrity: sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + resolution: {integrity: sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + resolution: {integrity: sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + resolution: {integrity: sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + resolution: {integrity: sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + resolution: {integrity: sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + resolution: {integrity: sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + resolution: {integrity: sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + resolution: {integrity: sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + resolution: {integrity: sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + resolution: {integrity: sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + resolution: {integrity: sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + resolution: {integrity: sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + resolution: {integrity: sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + resolution: {integrity: sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==} + cpu: [arm64] + os: [openharmony] + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + resolution: {integrity: sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + resolution: {integrity: sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + resolution: {integrity: sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + resolution: {integrity: sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==} + cpu: [x64] + os: [win32] + + '@vitejs/plugin-react@5.2.0': + resolution: {integrity: sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + + '@vitest/expect@4.1.8': + resolution: {integrity: sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==} + + '@vitest/mocker@4.1.8': + resolution: {integrity: sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.8': + resolution: {integrity: sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==} + + '@vitest/runner@4.1.8': + resolution: {integrity: sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==} + + '@vitest/snapshot@4.1.8': + resolution: {integrity: sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==} + + '@vitest/spy@4.1.8': + resolution: {integrity: sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==} + + '@vitest/utils@4.1.8': + resolution: {integrity: sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + engines: {node: '>=0.4.0'} + hasBin: true + + adler-32@1.3.1: + resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==} + engines: {node: '>=0.8'} + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + agentation-mcp@1.2.0: + resolution: {integrity: sha512-BRHVm/YRyAHzJFM8i+ZbgpLgpnVptyKeUyauYd2pkOBX/oVFYGOjjLU+YtpNZD1Np+5/jJAp9xFbv1SE112Wwg==} + engines: {node: '>=18.0.0'} + hasBin: true + + agentation@3.0.2: + resolution: {integrity: sha512-iGzBxFVTuZEIKzLY6AExSLAQH6i6SwxV4pAu7v7m3X6bInZ7qlZXAwrEqyc4+EfP4gM7z2RXBF6SF4DeH0f2lA==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + attr-accept@2.2.5: + resolution: {integrity: sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==} + engines: {node: '>=4'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axe-core@4.12.1: + resolution: {integrity: sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==} + engines: {node: '>=4'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.10.37: + resolution: {integrity: sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==} + engines: {node: '>=6.0.0'} + hasBin: true + + better-sqlite3@12.10.0: + resolution: {integrity: sha512-CyzaZRQKyHkB2ZInfTTl2nvT33EbDpjkLEbE8/Zck3Ll6O0qqvuGdrJ45HgtH+HykRg88ITY3AdreBGN70aBSQ==} + engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x || 26.x} + + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + + brace-expansion@1.1.15: + resolution: {integrity: sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==} + + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + engines: {node: 18 || 20 || >=22} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001799: + resolution: {integrity: sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==} + + cfb@1.2.2: + resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==} + engines: {node: '>=0.8'} + + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + codepage@1.15.0: + resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==} + engines: {node: '>=0.8'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + content-type@2.0.0: + resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + engines: {node: '>=18'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + cross-env@10.1.0: + resolution: {integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==} + engines: {node: '>=20'} + hasBin: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + + cssstyle@6.2.0: + resolution: {integrity: sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig==} + engines: {node: '>=20'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + + data-urls@7.0.0: + resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + + dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.5.372: + resolution: {integrity: sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + enhanced-resolve@5.21.6: + resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==} + engines: {node: '>=10.13.0'} + + entities@8.0.0: + resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} + engines: {node: '>=20.19.0'} + + es-abstract@1.24.2: + resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-iterator-helpers@1.3.3: + resolution: {integrity: sha512-0PuBxFi+4uPanB97iDxCLWuHeYud2FALrw5HFZGtAF38UpJDbDC8frwp2cnDyae692CQ0dou60UwWfhgsa4U/g==} + engines: {node: '>= 0.4'} + + es-module-lexer@2.1.0: + resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-next@16.0.6: + resolution: {integrity: sha512-nx0Z2S50TlcSQ2RtyULCff5tlKTwqF/ICh3U9s8C/e2aRXAm1Ootdb7BEHGZmejtJSgsFq8PVFdlWy8BHiz2pg==} + peerDependencies: + eslint: '>=9.0.0' + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + + eslint-import-resolver-node@0.3.10: + resolution: {integrity: sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==} + + eslint-import-resolver-typescript@3.10.1: + resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.13.0: + resolution: {integrity: sha512-bLohSkT6469rRs8czj0tLTD8vaeIS/whvPRJVjDr7IuoTT1k5DYDERlNycjDj/HkOlvQdYurmfZ/g3fG5bgeLQ==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-jsx-a11y@6.10.2: + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + + eslint-plugin-react-hooks@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 + + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.39.4: + resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventsource-parser@3.1.0: + resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + + express-rate-limit@8.5.2: + resolution: {integrity: sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-uri@3.1.2: + resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + file-selector@2.1.2: + resolution: {integrity: sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==} + engines: {node: '>= 12'} + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + frac@1.1.2: + resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==} + engines: {node: '>=0.8'} + + framer-motion@11.18.2: + resolution: {integrity: sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.2.0: + resolution: {integrity: sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} + + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@16.4.0: + resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + + hono@4.12.25: + resolution: {integrity: sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ==} + engines: {node: '>=16.9.0'} + + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + + icu-minify@4.13.0: + resolution: {integrity: sha512-SIFMeUHZJjzS5RvIGvybKvWoHjDm9cGVEs2EpJ8PmywOdJLWyblPm7TdPLLoUtkJtwQD7iGhl2WMptZ+N0on+w==} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + intl-messageformat@11.2.8: + resolution: {integrity: sha512-l323RCl3qJDVQ8U9j74ut/hVMdg3VPsOHpVMDvFfz9qiq4dPO5ooVYFNVUzzrpgG39a+RLzcXyJb8VFgIU+tUA==} + + ip-address@10.2.0: + resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-bun-module@2.0.0: + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-document.all@1.0.0: + resolution: {integrity: sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + jose@6.2.3: + resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.2.0: + resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} + hasBin: true + + jsdom@28.1.0: + resolution: {integrity: sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + loglevel@1.9.2: + resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} + engines: {node: '>= 0.6.0'} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@11.5.1: + resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} + engines: {node: 20 || >=22} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@0.555.0: + resolution: {integrity: sha512-D8FvHUGbxWBRQM90NZeIyhAvkFfsh3u9ekrMvJ30Z6gnpBHS6HC6ldLg7tL45hwiIz/u66eKDtdA23gwwGsAHA==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + + motion-dom@11.18.1: + resolution: {integrity: sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==} + + motion-utils@11.18.1: + resolution: {integrity: sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + next-intl-swc-plugin-extractor@4.13.0: + resolution: {integrity: sha512-6S/fJI0KXvLCL8nhBo9P8eGaJPzmwJBTCzX0NaUIj0VyU8U89d//T+vjMLdNIXl5MlLaYH7B9MbAjb8Mvu+tqQ==} + + next-intl@4.13.0: + resolution: {integrity: sha512-OvNq2v5XLx4EkQOsAhVE9g+6zdb83XHusADCXXtIW4LILYnjEVaeINdr1lkVWKSjzwNUiMSlH5N4K0OQTRiv6A==} + peerDependencies: + next: ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + next-themes@0.4.6: + resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + + next@16.0.6: + resolution: {integrity: sha512-2zOZ/4FdaAp5hfCU/RnzARlZzBsjaTZ/XjNQmuyYLluAPM7kcrbIkdeO2SL0Ysd1vnrSgU+GwugfeWX1cUCgCg==} + engines: {node: '>=20.9.0'} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details. + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-abi@3.92.0: + resolution: {integrity: sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==} + engines: {node: '>=10'} + + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + node-exports-info@1.6.0: + resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==} + engines: {node: '>= 0.4'} + + node-releases@2.0.47: + resolution: {integrity: sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==} + engines: {node: '>=18'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + + obug@2.1.3: + resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} + engines: {node: '>=12.20.0'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse5@8.0.1: + resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + + po-parser@2.1.1: + resolution: {integrity: sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. + hasBin: true + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.15.2: + resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} + engines: {node: '>=0.6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + react-dom@19.2.0: + resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} + peerDependencies: + react: ^19.2.0 + + react-dropzone@14.4.1: + resolution: {integrity: sha512-QDuV76v3uKbHiH34SpwifZ+gOLi1+RdsCO1kl5vxMT4wW8R82+sthjvBw4th3NHF/XX6FBsqDYZVNN+pnhaw0g==} + engines: {node: '>= 10.13'} + peerDependencies: + react: '>= 16.8 || 18.0.0' + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} + engines: {node: '>=0.10.0'} + + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.2: + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react@19.2.0: + resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} + engines: {node: '>=0.10.0'} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@2.0.0-next.7: + resolution: {integrity: sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==} + engines: {node: '>= 0.4'} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rolldown@1.0.3: + resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.4: + resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} + engines: {node: '>=0.4'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.8.4: + resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + ssf@0.11.2: + resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==} + engines: {node: '>=0.8'} + + stable-hash@0.0.5: + resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + string.prototype.includes@2.0.1: + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} + engines: {node: '>= 0.4'} + + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.11: + resolution: {integrity: sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.10: + resolution: {integrity: sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + + tailwind-merge@3.6.0: + resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} + + tailwindcss@4.3.1: + resolution: {integrity: sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + engines: {node: '>=18'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + + tldts-core@7.4.2: + resolution: {integrity: sha512-nwEyF4vl4RSJjwSjBUmOSxc3BFPoIFdlRthJ6e+5v9P3bHNsoD06UjuqMUspqp7vsEZ1beaHi1km+optiE17yA==} + + tldts@7.4.2: + resolution: {integrity: sha512-kCwffuaH8ntKtygnWe1b4BJKWiCUH30n5KfoTr6IchcXOwR7chAOFJxFrH3vjANafUYrIA4a7SDL+nn7SiR4Sw==} + hasBin: true + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tough-cookie@6.0.1: + resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} + engines: {node: '>=16'} + + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} + + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + tw-animate-css@1.4.0: + resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.8: + resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} + engines: {node: '>= 0.4'} + + typescript-eslint@8.61.0: + resolution: {integrity: sha512-8y31Rd0eGTrDKqhy6vT0HtzhN+YLjQizwX3aA3hPXP/ynSfnrBXcQY5IzsP9/DM7+klX4IUncZZjkchP0z+rUw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + undici@7.27.2: + resolution: {integrity: sha512-uZsKNuzQxDMUY6M3pIMvy5tvlGmtq8XJ2oLAkfRKGNu+1VQAIvLy2xIVG5ATZl5wDXl/tddByAWCizRbOme+TA==} + engines: {node: '>=20.18.1'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + unrs-resolver@1.12.2: + resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-intl@4.13.0: + resolution: {integrity: sha512-fAFDrWaASxlhXOipcOyb5VDD+YONqj6+8O8EcG/J7RBoOUF3A8YahRWLN+mBxYMrlMQB8N6Voqk5X+YC+HSL0A==} + peerDependencies: + react: ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0 + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vite@8.0.16: + resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.18 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.1.8: + resolution: {integrity: sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.8 + '@vitest/browser-preview': 4.1.8 + '@vitest/browser-webdriverio': 4.1.8 + '@vitest/coverage-istanbul': 4.1.8 + '@vitest/coverage-v8': 4.1.8 + '@vitest/ui': 4.1.8 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} + engines: {node: '>=20'} + + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} + engines: {node: '>=20'} + + whatwg-url@16.0.1: + resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.22: + resolution: {integrity: sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + wmf@1.0.2: + resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==} + engines: {node: '>=0.8'} + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + word@0.3.0: + resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==} + engines: {node: '>=0.8'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + xlsx@0.18.5: + resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==} + engines: {node: '>=0.8'} + hasBin: true + + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + + zustand@5.0.14: + resolution: {integrity: sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + +snapshots: + + '@acemir/cssom@0.9.31': {} + + '@adobe/css-tools@4.5.0': {} + + '@alloc/quick-lru@5.2.0': {} + + '@asamuzakjp/css-color@5.1.11': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.1.3(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@asamuzakjp/dom-selector@6.8.1': + dependencies: + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.2.1 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.5.1 + + '@asamuzakjp/generational-cache@1.0.1': {} + + '@asamuzakjp/nwsapi@2.3.9': {} + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.7': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.29.7': {} + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/plugin-transform-react-jsx-self@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-react-jsx-source@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/runtime@7.29.7': {} + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/traverse@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@bramus/specificity@2.4.2': + dependencies: + css-tree: 3.2.1 + + '@csstools/color-helpers@6.0.2': {} + + '@csstools/css-calc@3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-color-parser@4.1.3(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/color-helpers': 6.0.2 + '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.5(css-tree@3.2.1)': + optionalDependencies: + css-tree: 3.2.1 + + '@csstools/css-tokenizer@4.0.0': {} + + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@epic-web/invariant@1.0.0': {} + + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': + dependencies: + eslint: 9.39.4(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.2': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.5': + dependencies: + ajv: 6.15.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.2.0 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.4': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@exodus/bytes@1.15.1': {} + + '@floating-ui/core@1.7.5': + dependencies: + '@floating-ui/utils': 0.2.11 + + '@floating-ui/dom@1.7.6': + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 + + '@floating-ui/react-dom@2.1.8(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@floating-ui/dom': 1.7.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@floating-ui/utils@0.2.11': {} + + '@formatjs/fast-memoize@3.1.6': {} + + '@formatjs/icu-messageformat-parser@3.5.11': + dependencies: + '@formatjs/icu-skeleton-parser': 2.1.10 + + '@formatjs/icu-skeleton-parser@2.1.10': {} + + '@formatjs/intl-localematcher@0.8.10': + dependencies: + '@formatjs/fast-memoize': 3.1.6 + + '@hono/node-server@1.19.14(hono@4.12.25)': + dependencies: + hono: 4.12.25 + + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@img/colour@1.1.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.11.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@mlc-ai/web-llm@0.2.84': + dependencies: + loglevel: 1.9.2 + + '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': + dependencies: + '@hono/node-server': 1.19.14(hono@4.12.25) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.1.0 + express: 5.2.1 + express-rate-limit: 8.5.2(express@5.2.1) + hono: 4.12.25 + jose: 6.2.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + transitivePeerDependencies: + - supports-color + + '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 + optional: true + + '@next/env@16.0.6': {} + + '@next/eslint-plugin-next@16.0.6': + dependencies: + fast-glob: 3.3.1 + + '@next/swc-darwin-arm64@16.0.6': + optional: true + + '@next/swc-darwin-x64@16.0.6': + optional: true + + '@next/swc-linux-arm64-gnu@16.0.6': + optional: true + + '@next/swc-linux-arm64-musl@16.0.6': + optional: true + + '@next/swc-linux-x64-gnu@16.0.6': + optional: true + + '@next/swc-linux-x64-musl@16.0.6': + optional: true + + '@next/swc-win32-arm64-msvc@16.0.6': + optional: true + + '@next/swc-win32-x64-msvc@16.0.6': + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@nolyfill/is-core-module@1.0.39': {} + + '@oxc-project/types@0.133.0': {} + + '@parcel/watcher-android-arm64@2.5.6': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.6': + optional: true + + '@parcel/watcher-darwin-x64@2.5.6': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.6': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.6': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.6': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.6': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.6': + optional: true + + '@parcel/watcher-win32-arm64@2.5.6': + optional: true + + '@parcel/watcher-win32-ia32@2.5.6': + optional: true + + '@parcel/watcher-win32-x64@2.5.6': + optional: true + + '@parcel/watcher@2.5.6': + dependencies: + detect-libc: 2.1.2 + is-glob: 4.0.3 + node-addon-api: 7.1.1 + picomatch: 4.0.4 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.6 + '@parcel/watcher-darwin-arm64': 2.5.6 + '@parcel/watcher-darwin-x64': 2.5.6 + '@parcel/watcher-freebsd-x64': 2.5.6 + '@parcel/watcher-linux-arm-glibc': 2.5.6 + '@parcel/watcher-linux-arm-musl': 2.5.6 + '@parcel/watcher-linux-arm64-glibc': 2.5.6 + '@parcel/watcher-linux-arm64-musl': 2.5.6 + '@parcel/watcher-linux-x64-glibc': 2.5.6 + '@parcel/watcher-linux-x64-musl': 2.5.6 + '@parcel/watcher-win32-arm64': 2.5.6 + '@parcel/watcher-win32-ia32': 2.5.6 + '@parcel/watcher-win32-x64': 2.5.6 + + '@radix-ui/number@1.1.2': {} + + '@radix-ui/primitive@1.1.4': {} + + '@radix-ui/react-arrow@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-avatar@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-is-hydrated': 0.1.1(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-checkbox@1.3.4(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-collection@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.5(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-compose-refs@1.1.3(@types/react@19.2.17)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-context@1.1.4(@types/react@19.2.17)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-dialog@1.1.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-portal': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.5(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-direction@1.1.2(@types/react@19.2.17)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-dismissable-layer@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-escape-keydown': 1.1.2(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-dropdown-menu@2.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-menu': 2.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-focus-guards@1.1.4(@types/react@19.2.17)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-focus-scope@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-id@1.1.2(@types/react@19.2.17)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-label@2.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-menu@2.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-collection': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-popper': 1.3.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-roving-focus': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.5(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-popper@1.3.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-arrow': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-rect': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/rect': 1.1.2 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-portal@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-presence@1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-primitive@2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-slot': 1.2.5(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-progress@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-roving-focus@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-collection': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-scroll-area@1.2.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/number': 1.1.2 + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-select@2.3.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/number': 1.1.2 + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-collection': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-popper': 1.3.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.5(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-visually-hidden': 1.2.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-separator@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-slot@1.2.5(@types/react@19.2.17)(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-switch@1.3.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-previous': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-tabs@1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-roving-focus': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-toast@1.2.16(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-collection': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-visually-hidden': 1.2.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-tooltip@1.2.9(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-popper': 1.3.0(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.5(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-visually-hidden': 1.2.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-use-callback-ref@1.1.2(@types/react@19.2.17)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-controllable-state@1.2.3(@types/react@19.2.17)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-effect-event@0.0.3(@types/react@19.2.17)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-escape-keydown@1.1.2(@types/react@19.2.17)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-is-hydrated@0.1.1(@types/react@19.2.17)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-layout-effect@1.1.2(@types/react@19.2.17)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-previous@1.1.2(@types/react@19.2.17)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-rect@1.1.2(@types/react@19.2.17)(react@19.2.0)': + dependencies: + '@radix-ui/rect': 1.1.2 + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-size@1.1.2(@types/react@19.2.17)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-visually-hidden@1.2.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.5(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/rect@1.1.2': {} + + '@react-oauth/google@0.13.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rolldown/binding-android-arm64@1.0.3': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.3': + optional: true + + '@rolldown/binding-darwin-x64@1.0.3': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.3': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.3': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.3': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.3': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.3': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.3': + optional: true + + '@rolldown/pluginutils@1.0.0-rc.3': {} + + '@rolldown/pluginutils@1.0.1': {} + + '@rtsao/scc@1.1.0': {} + + '@schummar/icu-type-parser@1.21.5': {} + + '@standard-schema/spec@1.1.0': {} + + '@swc/core-darwin-arm64@1.15.41': + optional: true + + '@swc/core-darwin-x64@1.15.41': + optional: true + + '@swc/core-linux-arm-gnueabihf@1.15.41': + optional: true + + '@swc/core-linux-arm64-gnu@1.15.41': + optional: true + + '@swc/core-linux-arm64-musl@1.15.41': + optional: true + + '@swc/core-linux-ppc64-gnu@1.15.41': + optional: true + + '@swc/core-linux-s390x-gnu@1.15.41': + optional: true + + '@swc/core-linux-x64-gnu@1.15.41': + optional: true + + '@swc/core-linux-x64-musl@1.15.41': + optional: true + + '@swc/core-win32-arm64-msvc@1.15.41': + optional: true + + '@swc/core-win32-ia32-msvc@1.15.41': + optional: true + + '@swc/core-win32-x64-msvc@1.15.41': + optional: true + + '@swc/core@1.15.41': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.26 + optionalDependencies: + '@swc/core-darwin-arm64': 1.15.41 + '@swc/core-darwin-x64': 1.15.41 + '@swc/core-linux-arm-gnueabihf': 1.15.41 + '@swc/core-linux-arm64-gnu': 1.15.41 + '@swc/core-linux-arm64-musl': 1.15.41 + '@swc/core-linux-ppc64-gnu': 1.15.41 + '@swc/core-linux-s390x-gnu': 1.15.41 + '@swc/core-linux-x64-gnu': 1.15.41 + '@swc/core-linux-x64-musl': 1.15.41 + '@swc/core-win32-arm64-msvc': 1.15.41 + '@swc/core-win32-ia32-msvc': 1.15.41 + '@swc/core-win32-x64-msvc': 1.15.41 + + '@swc/counter@0.1.3': {} + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@swc/types@0.1.26': + dependencies: + '@swc/counter': 0.1.3 + + '@tailwindcss/node@4.3.1': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.21.6 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.1 + + '@tailwindcss/oxide-android-arm64@4.3.1': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.1': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.1': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.1': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.1': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.1': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.1': + optional: true + + '@tailwindcss/oxide@4.3.1': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.1 + '@tailwindcss/oxide-darwin-arm64': 4.3.1 + '@tailwindcss/oxide-darwin-x64': 4.3.1 + '@tailwindcss/oxide-freebsd-x64': 4.3.1 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.1 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.1 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.1 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.1 + '@tailwindcss/oxide-linux-x64-musl': 4.3.1 + '@tailwindcss/oxide-wasm32-wasi': 4.3.1 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.1 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.1 + + '@tailwindcss/postcss@4.3.1': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.3.1 + '@tailwindcss/oxide': 4.3.1 + postcss: 8.5.15 + tailwindcss: 4.3.1 + + '@tanstack/query-core@5.101.0': {} + + '@tanstack/react-query@5.101.0(react@19.2.0)': + dependencies: + '@tanstack/query-core': 5.101.0 + react: 19.2.0 + + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/runtime': 7.29.7 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + '@testing-library/jest-dom@6.9.1': + dependencies: + '@adobe/css-tools': 4.5.0 + aria-query: 5.3.2 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + picocolors: 1.1.1 + redent: 3.0.0 + + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@babel/runtime': 7.29.7 + '@testing-library/dom': 10.4.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@tybys/wasm-util@0.10.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/aria-query@5.0.4': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.29.7 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.29.7 + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.9': {} + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/node@20.19.43': + dependencies: + undici-types: 6.21.0 + + '@types/react-dom@19.2.3(@types/react@19.2.17)': + dependencies: + '@types/react': 19.2.17 + + '@types/react@19.2.17': + dependencies: + csstype: 3.2.3 + + '@typescript-eslint/eslint-plugin@8.61.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/type-utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.61.0 + eslint: 9.39.4(jiti@2.7.0) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/typescript-estree': 8.61.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.61.0 + debug: 4.4.3 + eslint: 9.39.4(jiti@2.7.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.61.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.61.0(typescript@5.9.3) + '@typescript-eslint/types': 8.61.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.61.0': + dependencies: + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/visitor-keys': 8.61.0 + + '@typescript-eslint/tsconfig-utils@8.61.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/typescript-estree': 8.61.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.4(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.61.0': {} + + '@typescript-eslint/typescript-estree@8.61.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.61.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.61.0(typescript@5.9.3) + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/visitor-keys': 8.61.0 + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.8.4 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.61.0 + '@typescript-eslint/types': 8.61.0 + '@typescript-eslint/typescript-estree': 8.61.0(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.61.0': + dependencies: + '@typescript-eslint/types': 8.61.0 + eslint-visitor-keys: 5.0.1 + + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + optional: true + + '@unrs/resolver-binding-android-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + optional: true + + '@vitejs/plugin-react@5.2.0(vite@8.0.16(@types/node@20.19.43)(jiti@2.7.0))': + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.7) + '@rolldown/pluginutils': 1.0.0-rc.3 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: 8.0.16(@types/node@20.19.43)(jiti@2.7.0) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@4.1.8': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.8 + '@vitest/utils': 4.1.8 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.8(vite@8.0.16(@types/node@20.19.43)(jiti@2.7.0))': + dependencies: + '@vitest/spy': 4.1.8 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.16(@types/node@20.19.43)(jiti@2.7.0) + + '@vitest/pretty-format@4.1.8': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.8': + dependencies: + '@vitest/utils': 4.1.8 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.8': + dependencies: + '@vitest/pretty-format': 4.1.8 + '@vitest/utils': 4.1.8 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.8': {} + + '@vitest/utils@4.1.8': + dependencies: + '@vitest/pretty-format': 4.1.8 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + + acorn-jsx@5.3.2(acorn@8.17.0): + dependencies: + acorn: 8.17.0 + + acorn@8.17.0: {} + + adler-32@1.3.1: {} + + agent-base@7.1.4: {} + + agentation-mcp@1.2.0: + dependencies: + '@modelcontextprotocol/sdk': 1.29.0(zod@3.25.76) + better-sqlite3: 12.10.0 + zod: 3.25.76 + transitivePeerDependencies: + - '@cfworker/json-schema' + - supports-color + + agentation@3.0.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + optionalDependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.2 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + argparse@2.0.1: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-shim-unscopables: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + assertion-error@2.0.1: {} + + ast-types-flow@0.0.8: {} + + async-function@1.0.0: {} + + attr-accept@2.2.5: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axe-core@4.12.1: {} + + axobject-query@4.1.0: {} + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.10.37: {} + + better-sqlite3@12.10.0: + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.3 + + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.15.2 + raw-body: 3.0.2 + type-is: 2.1.0 + transitivePeerDependencies: + - supports-color + + brace-expansion@1.1.15: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@5.0.6: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.37 + caniuse-lite: 1.0.30001799 + electron-to-chromium: 1.5.372 + node-releases: 2.0.47 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + bytes@3.1.2: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.9: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001799: {} + + cfb@1.2.2: + dependencies: + adler-32: 1.3.1 + crc-32: 1.2.2 + + chai@6.2.2: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chownr@1.1.4: {} + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + client-only@0.0.1: {} + + clsx@2.1.1: {} + + codepage@1.15.0: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + content-disposition@1.1.0: {} + + content-type@1.0.5: {} + + content-type@2.0.0: {} + + convert-source-map@2.0.0: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + crc-32@1.2.2: {} + + cross-env@10.1.0: + dependencies: + '@epic-web/invariant': 1.0.0 + cross-spawn: 7.0.6 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + + css.escape@1.5.1: {} + + cssstyle@6.2.0: + dependencies: + '@asamuzakjp/css-color': 5.1.11 + '@csstools/css-syntax-patches-for-csstree': 1.1.5(css-tree@3.2.1) + css-tree: 3.2.1 + lru-cache: 11.5.1 + + csstype@3.2.3: {} + + damerau-levenshtein@1.0.8: {} + + data-urls@7.0.0: + dependencies: + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + transitivePeerDependencies: + - '@noble/hashes' + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decimal.js@10.6.0: {} + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deep-extend@0.6.0: {} + + deep-is@0.1.4: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + depd@2.0.0: {} + + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + + detect-node-es@1.1.0: {} + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + dom-accessibility-api@0.5.16: {} + + dom-accessibility-api@0.6.3: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + ee-first@1.1.1: {} + + electron-to-chromium@1.5.372: {} + + emoji-regex@9.2.2: {} + + encodeurl@2.0.0: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + enhanced-resolve@5.21.6: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + entities@8.0.0: {} + + es-abstract@1.24.2: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.2.0 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.4 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.11 + string.prototype.trimend: 1.0.10 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.8 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.22 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-iterator-helpers@1.3.3: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + math-intrinsics: 1.1.0 + + es-module-lexer@2.1.0: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.4 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-next@16.0.6(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): + dependencies: + '@next/eslint-plugin-next': 16.0.6 + eslint: 9.39.4(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-react-hooks: 7.1.1(eslint@9.39.4(jiti@2.7.0)) + globals: 16.4.0 + typescript-eslint: 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + + eslint-import-resolver-node@0.3.10: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.2 + resolve: 2.0.0-next.7 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.3 + eslint: 9.39.4(jiti@2.7.0) + get-tsconfig: 4.14.0 + is-bun-module: 2.0.0 + stable-hash: 0.0.5 + tinyglobby: 0.2.17 + unrs-resolver: 1.12.2 + optionalDependencies: + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.13.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.39.4(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-module-utils: 2.13.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + hasown: 2.0.4 + is-core-module: 2.16.2 + is-glob: 4.0.3 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.10 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.4(jiti@2.7.0)): + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + ast-types-flow: 0.0.8 + axe-core: 4.12.1 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 9.39.4(jiti@2.7.0) + hasown: 2.0.4 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 + + eslint-plugin-react-hooks@7.1.1(eslint@9.39.4(jiti@2.7.0)): + dependencies: + '@babel/core': 7.29.7 + '@babel/parser': 7.29.7 + eslint: 9.39.4(jiti@2.7.0) + hermes-parser: 0.25.1 + zod: 4.4.3 + zod-validation-error: 4.0.2(zod@4.4.3) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@2.7.0)): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.3.3 + eslint: 9.39.4(jiti@2.7.0) + estraverse: 5.3.0 + hasown: 2.0.4 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.5 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.7 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@9.39.4(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.2 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.5 + '@eslint/js': 9.39.4 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 + ajv: 6.15.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + esutils@2.0.3: {} + + etag@1.8.1: {} + + eventsource-parser@3.1.0: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.1.0 + + expand-template@2.0.3: {} + + expect-type@1.3.0: {} + + express-rate-limit@8.5.2(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.2.0 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.2 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.1.0 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.1: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-uri@3.1.2: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + file-selector@2.1.2: + dependencies: + tslib: 2.8.1 + + file-uri-to-path@1.0.0: {} + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.4.2 + keyv: 4.5.4 + + flatted@3.4.2: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + forwarded@0.2.0: {} + + frac@1.1.2: {} + + framer-motion@11.18.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + motion-dom: 11.18.1 + motion-utils: 11.18.1 + tslib: 2.8.1 + optionalDependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + fresh@2.0.0: {} + + fs-constants@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.2.0: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + es-define-property: 1.0.1 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + hasown: 2.0.4 + is-callable: 1.2.7 + is-document.all: 1.0.0 + + functions-have-names@1.2.3: {} + + generator-function@2.0.1: {} + + gensync@1.0.0-beta.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-nonce@1.0.1: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + get-tsconfig@4.14.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + github-from-package@0.0.0: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globals@16.4.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + + hono@4.12.25: {} + + html-encoding-sniffer@6.0.0: + dependencies: + '@exodus/bytes': 1.15.1 + transitivePeerDependencies: + - '@noble/hashes' + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + + icu-minify@4.13.0: + dependencies: + '@formatjs/icu-messageformat-parser': 3.5.11 + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + indent-string@4.0.0: {} + + inherits@2.0.4: {} + + ini@1.3.8: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.4 + side-channel: 1.1.1 + + intl-messageformat@11.2.8: + dependencies: + '@formatjs/fast-memoize': 3.1.6 + '@formatjs/icu-messageformat-parser': 3.5.11 + + ip-address@10.2.0: {} + + ipaddr.js@1.9.1: {} + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-bun-module@2.0.0: + dependencies: + semver: 7.8.4 + + is-callable@1.2.7: {} + + is-core-module@2.16.2: + dependencies: + hasown: 2.0.4 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-document.all@1.0.0: + dependencies: + call-bound: 1.0.4 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-potential-custom-element-name@1.0.1: {} + + is-promise@4.0.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.22 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + + jiti@2.7.0: {} + + jose@6.2.3: {} + + js-tokens@4.0.0: {} + + js-yaml@4.2.0: + dependencies: + argparse: 2.0.1 + + jsdom@28.1.0: + dependencies: + '@acemir/cssom': 0.9.31 + '@asamuzakjp/dom-selector': 6.8.1 + '@bramus/specificity': 2.4.2 + '@exodus/bytes': 1.15.1 + cssstyle: 6.2.0 + data-urls: 7.0.0 + decimal.js: 10.6.0 + html-encoding-sniffer: 6.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-potential-custom-element-name: 1.0.1 + parse5: 8.0.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.1 + undici: 7.27.2 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - '@noble/hashes' + - supports-color + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + json5@2.2.3: {} + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + language-subtag-registry@0.3.23: {} + + language-tags@1.0.9: + dependencies: + language-subtag-registry: 0.3.23 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + loglevel@1.9.2: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@11.5.1: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@0.555.0(react@19.2.0): + dependencies: + react: 19.2.0 + + lz-string@1.5.0: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + math-intrinsics@1.1.0: {} + + mdn-data@2.27.1: {} + + media-typer@1.1.0: {} + + merge-descriptors@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + mime-db@1.54.0: {} + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + mimic-response@3.1.0: {} + + min-indent@1.0.1: {} + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.6 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.15 + + minimist@1.2.8: {} + + mkdirp-classic@0.5.3: {} + + motion-dom@11.18.1: + dependencies: + motion-utils: 11.18.1 + + motion-utils@11.18.1: {} + + ms@2.1.3: {} + + nanoid@3.3.12: {} + + napi-build-utils@2.0.0: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + negotiator@1.0.0: {} + + next-intl-swc-plugin-extractor@4.13.0: {} + + next-intl@4.13.0(next@16.0.6(@babel/core@7.29.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(typescript@5.9.3): + dependencies: + '@formatjs/intl-localematcher': 0.8.10 + '@parcel/watcher': 2.5.6 + '@swc/core': 1.15.41 + icu-minify: 4.13.0 + negotiator: 1.0.0 + next: 16.0.6(@babel/core@7.29.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + next-intl-swc-plugin-extractor: 4.13.0 + po-parser: 2.1.1 + react: 19.2.0 + use-intl: 4.13.0(react@19.2.0) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@swc/helpers' + + next-themes@0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + next@16.0.6(@babel/core@7.29.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + '@next/env': 16.0.6 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001799 + postcss: 8.4.31 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + styled-jsx: 5.1.6(@babel/core@7.29.7)(react@19.2.0) + optionalDependencies: + '@next/swc-darwin-arm64': 16.0.6 + '@next/swc-darwin-x64': 16.0.6 + '@next/swc-linux-arm64-gnu': 16.0.6 + '@next/swc-linux-arm64-musl': 16.0.6 + '@next/swc-linux-x64-gnu': 16.0.6 + '@next/swc-linux-x64-musl': 16.0.6 + '@next/swc-win32-arm64-msvc': 16.0.6 + '@next/swc-win32-x64-msvc': 16.0.6 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + node-abi@3.92.0: + dependencies: + semver: 7.8.4 + + node-addon-api@7.1.1: {} + + node-exports-info@1.6.0: + dependencies: + array.prototype.flatmap: 1.3.3 + es-errors: 1.3.0 + object.entries: 1.1.9 + semver: 6.3.1 + + node-releases@2.0.47: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + obug@2.1.3: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse5@8.0.1: + dependencies: + entities: 8.0.0 + + parseurl@1.3.3: {} + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-to-regexp@8.4.2: {} + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.4: {} + + pkce-challenge@5.0.1: {} + + po-parser@2.1.1: {} + + possible-typed-array-names@1.1.0: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prebuild-install@7.1.3: + dependencies: + detect-libc: 2.1.2 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 2.0.0 + node-abi: 3.92.0 + pump: 3.0.4 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.4 + tunnel-agent: 0.6.0 + + prelude-ls@1.2.1: {} + + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + punycode@2.3.1: {} + + qs@6.15.2: + dependencies: + side-channel: 1.1.1 + + queue-microtask@1.2.3: {} + + range-parser@1.2.1: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + + react-dom@19.2.0(react@19.2.0): + dependencies: + react: 19.2.0 + scheduler: 0.27.0 + + react-dropzone@14.4.1(react@19.2.0): + dependencies: + attr-accept: 2.2.5 + file-selector: 2.1.2 + prop-types: 15.8.1 + react: 19.2.0 + + react-is@16.13.1: {} + + react-is@17.0.2: {} + + react-refresh@0.18.0: {} + + react-remove-scroll-bar@2.3.8(@types/react@19.2.17)(react@19.2.0): + dependencies: + react: 19.2.0 + react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.0) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + + react-remove-scroll@2.7.2(@types/react@19.2.17)(react@19.2.0): + dependencies: + react: 19.2.0 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.17)(react@19.2.0) + react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.0) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.17)(react@19.2.0) + use-sidecar: 1.1.3(@types/react@19.2.17)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.17 + + react-style-singleton@2.2.3(@types/react@19.2.17)(react@19.2.0): + dependencies: + get-nonce: 1.0.1 + react: 19.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + + react@19.2.0: {} + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@2.0.0-next.7: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.2 + node-exports-info: 1.6.0 + object-keys: 1.1.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + rolldown@1.0.3: + dependencies: + '@oxc-project/types': 0.133.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.3 + '@rolldown/binding-darwin-arm64': 1.0.3 + '@rolldown/binding-darwin-x64': 1.0.3 + '@rolldown/binding-freebsd-x64': 1.0.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 + '@rolldown/binding-linux-arm64-gnu': 1.0.3 + '@rolldown/binding-linux-arm64-musl': 1.0.3 + '@rolldown/binding-linux-ppc64-gnu': 1.0.3 + '@rolldown/binding-linux-s390x-gnu': 1.0.3 + '@rolldown/binding-linux-x64-gnu': 1.0.3 + '@rolldown/binding-linux-x64-musl': 1.0.3 + '@rolldown/binding-openharmony-arm64': 1.0.3 + '@rolldown/binding-wasm32-wasi': 1.0.3 + '@rolldown/binding-win32-arm64-msvc': 1.0.3 + '@rolldown/binding-win32-x64-msvc': 1.0.3 + + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.4: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-buffer@5.2.1: {} + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safer-buffer@2.1.2: {} + + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + + scheduler@0.27.0: {} + + semver@6.3.1: {} + + semver@7.8.4: {} + + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + + setprototypeof@1.2.0: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.4 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + siginfo@2.0.0: {} + + simple-concat@1.0.1: {} + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + + source-map-js@1.2.1: {} + + ssf@0.11.2: + dependencies: + frac: 1.1.2 + + stable-hash@0.0.5: {} + + stackback@0.0.2: {} + + statuses@2.0.2: {} + + std-env@4.1.0: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + string.prototype.includes@2.0.1: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.1 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.2 + + string.prototype.trim@1.2.11: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + has-property-descriptors: 1.0.2 + safe-regex-test: 1.1.0 + + string.prototype.trimend@1.0.10: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-bom@3.0.0: {} + + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + + strip-json-comments@2.0.1: {} + + strip-json-comments@3.1.1: {} + + styled-jsx@5.1.6(@babel/core@7.29.7)(react@19.2.0): + dependencies: + client-only: 0.0.1 + react: 19.2.0 + optionalDependencies: + '@babel/core': 7.29.7 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + symbol-tree@3.2.4: {} + + tailwind-merge@3.6.0: {} + + tailwindcss@4.3.1: {} + + tapable@2.3.3: {} + + tar-fs@2.1.4: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.4 + tar-stream: 2.2.0 + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + tinybench@2.9.0: {} + + tinyexec@1.2.4: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tinyrainbow@3.1.0: {} + + tldts-core@7.4.2: {} + + tldts@7.4.2: + dependencies: + tldts-core: 7.4.2 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + tough-cookie@6.0.1: + dependencies: + tldts: 7.4.2 + + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + + ts-api-utils@2.5.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: {} + + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + + tw-animate-css@1.4.0: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-is@2.1.0: + dependencies: + content-type: 2.0.0 + media-typer: 1.1.0 + mime-types: 3.0.2 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.8: + dependencies: + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript-eslint@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.61.0(@typescript-eslint/parser@8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.61.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.61.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript@5.9.3: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@6.21.0: {} + + undici@7.27.2: {} + + unpipe@1.0.0: {} + + unrs-resolver@1.12.2: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.12.2 + '@unrs/resolver-binding-android-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-x64': 1.12.2 + '@unrs/resolver-binding-freebsd-x64': 1.12.2 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-arm64-musl': 1.12.2 + '@unrs/resolver-binding-linux-loong64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-loong64-musl': 1.12.2 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-musl': 1.12.2 + '@unrs/resolver-binding-linux-s390x-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-musl': 1.12.2 + '@unrs/resolver-binding-openharmony-arm64': 1.12.2 + '@unrs/resolver-binding-wasm32-wasi': 1.12.2 + '@unrs/resolver-binding-win32-arm64-msvc': 1.12.2 + '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 + '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 + + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-callback-ref@1.3.3(@types/react@19.2.17)(react@19.2.0): + dependencies: + react: 19.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + + use-intl@4.13.0(react@19.2.0): + dependencies: + '@formatjs/fast-memoize': 3.1.6 + '@schummar/icu-type-parser': 1.21.5 + icu-minify: 4.13.0 + intl-messageformat: 11.2.8 + react: 19.2.0 + + use-sidecar@1.1.3(@types/react@19.2.17)(react@19.2.0): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + + util-deprecate@1.0.2: {} + + vary@1.1.2: {} + + vite@8.0.16(@types/node@20.19.43)(jiti@2.7.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.15 + rolldown: 1.0.3 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 20.19.43 + fsevents: 2.3.3 + jiti: 2.7.0 + + vitest@4.1.8(@types/node@20.19.43)(jsdom@28.1.0)(vite@8.0.16(@types/node@20.19.43)(jiti@2.7.0)): + dependencies: + '@vitest/expect': 4.1.8 + '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@20.19.43)(jiti@2.7.0)) + '@vitest/pretty-format': 4.1.8 + '@vitest/runner': 4.1.8 + '@vitest/snapshot': 4.1.8 + '@vitest/spy': 4.1.8 + '@vitest/utils': 4.1.8 + es-module-lexer: 2.1.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.3 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.1.0 + tinybench: 2.9.0 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 + tinyrainbow: 3.1.0 + vite: 8.0.16(@types/node@20.19.43)(jiti@2.7.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 20.19.43 + jsdom: 28.1.0 + transitivePeerDependencies: + - msw + + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + + webidl-conversions@8.0.1: {} + + whatwg-mimetype@5.0.0: {} + + whatwg-url@16.0.1: + dependencies: + '@exodus/bytes': 1.15.1 + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.2.0 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.22 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.22: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + wmf@1.0.2: {} + + word-wrap@1.2.5: {} + + word@0.3.0: {} + + wrappy@1.0.2: {} + + xlsx@0.18.5: + dependencies: + adler-32: 1.3.1 + cfb: 1.2.2 + codepage: 1.15.0 + crc-32: 1.2.2 + ssf: 0.11.2 + wmf: 1.0.2 + word: 0.3.0 + + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + + yallist@3.1.1: {} + + yocto-queue@0.1.0: {} + + zod-to-json-schema@3.25.2(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod-validation-error@4.0.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@3.25.76: {} + + zod@4.4.3: {} + + zustand@5.0.14(@types/react@19.2.17)(react@19.2.0): + optionalDependencies: + '@types/react': 19.2.17 + react: 19.2.0 diff --git a/frontend/src/lib/i18n.tsx b/frontend/src/lib/i18n.tsx index 06964ca..2e3c868 100644 --- a/frontend/src/lib/i18n.tsx +++ b/frontend/src/lib/i18n.tsx @@ -6,14096 +6,64 @@ import { useState, useCallback, useEffect, + useMemo, type ReactNode, } from "react"; -export type Locale = "en" | "fr" | "es" | "de" | "pt" | "it" | "nl" | "ru" | "ja" | "ko" | "zh" | "ar" | "fa"; +import enMessages from "./i18n/messages/en"; -const VALID_LOCALES: ReadonlyArray = ["en", "fr", "es", "de", "pt", "it", "nl", "ru", "ja", "ko", "zh", "ar", "fa"]; +export type Locale = + | "en" + | "fr" + | "es" + | "de" + | "pt" + | "it" + | "nl" + | "ru" + | "ja" + | "ko" + | "zh" + | "ar" + | "fa"; + +const VALID_LOCALES: ReadonlyArray = [ + "en", + "fr", + "es", + "de", + "pt", + "it", + "nl", + "ru", + "ja", + "ko", + "zh", + "ar", + "fa", +]; + +const DEFAULT_LOCALE: Locale = "en"; +const RTL_LOCALES: ReadonlyArray = ["ar", "fa"]; type TranslationParams = Record; -const messages: Record> = { - - en: { -"auth.brandName": "Wordly", - "dashboard.nav.translate": "Translate", - "dashboard.nav.profile": "My Profile", - "dashboard.nav.settings": "Settings", - "dashboard.nav.context": "Context", - "dashboard.nav.services": "Services", - "dashboard.nav.apiKeys": "API Keys", - "dashboard.nav.glossaries": "Glossaries & Context", - "dashboard.header.title": "Dashboard", - "dashboard.header.subtitle": "Manage your translations", - "dashboard.header.toggleMenu": "Menu", - "dashboard.header.profileTitle": "My profile", - "dashboard.sidebar.theme": "Theme", - "dashboard.sidebar.signOut": "Sign Out", - "dashboard.sidebar.backHome": "Back to Home", - "dashboard.sidebar.upgradeToPro": "Upgrade to Pro →", - "cookieConsent.title": "Cookies on Wordly", - "cookieConsent.description": "We use essential cookies so the app works (session, security, language). With your permission, we also use optional cookies to measure traffic and improve the product.", - "cookieConsent.acceptAll": "Accept all", - "cookieConsent.essentialOnly": "Essential only", - "cookieConsent.learnMore": "Learn more", - "landing.nav.why": "Why Us?", - "landing.nav.formats": "Formats", - "landing.nav.pricing": "Pricing", - "landing.nav.login": "Log in", - "landing.nav.startFree": "Start Free", - "landing.hero.tag": "Professional Document AI", - "landing.hero.titleLine1": "Translate your documents.", - "landing.hero.titleLine2": "Keep the formatting perfect.", - "landing.hero.description": "The only translator that preserves SmartArt, charts, tables of contents, shapes, and complex layouts — exactly as they were.", - "landing.hero.ctaMain": "Start Free — 2 docs/month", - "landing.hero.ctaSec": "See Offers", - "landing.hero.deleted": "Files deleted after 60 min", - "landing.hero.noHidden": "No hidden fees", - "landing.hero.preview": "Preview before payment", - "landing.hero.formattedOk": "Formatting OK", - "landing.hero.aiActive": "AI Translation active", - "landing.steps.title": "How it works?", - "landing.steps.subtitle": "Three steps. Zero formatting loss.", - "landing.steps.step1.num": "01", - "landing.steps.step1.title": "Upload your file", - "landing.steps.step1.desc": "Drag & drop your Excel, Word, PowerPoint or PDF document.", - "landing.steps.step2.num": "02", - "landing.steps.step2.title": "Pick language & engine", - "landing.steps.step2.desc": "Select target language and engine — classic or context-aware AI.", - "landing.steps.step3.num": "03", - "landing.steps.step3.title": "Download the result", - "landing.steps.step3.desc": "Get your translated document with formatting identical to the original.", - "landing.features.tag": "AI Translation Engine", - "landing.features.title": "Translation that understands your craft", - "landing.features.description": "Our AI models analyze context, respect your terminology, and even translate text inside images.", - "landing.features.context.title": "Industry Context", - "landing.features.context.desc": "Describe your field and get tailored translations, not generic ones.", - "landing.features.glossary.title": "Industry Glossaries", - "landing.features.glossary.desc": "Define your technical terms. CTA stays 'Air Handling Unit', never 'Call To Action'.", - "landing.features.vision.title": "Image Vision", - "landing.features.vision.desc": "Text embedded in images, diagrams and charts is detected and translated.", - "landing.features.demo.source": "Source (FR)", - "landing.features.demo.google": "Google Translate", - "landing.features.demo.ours": "Our AI", - "landing.layout.title": "Your formatting,", - "landing.layout.title2": "perfectly preserved", - "landing.layout.subtitle": "Other translators break your layout. We don't.", - "landing.layout.p1.title": "SmartArt & Diagrams", - "landing.layout.p1.desc": "Org charts, flowcharts, hierarchies — all translated identically.", - "landing.layout.p2.title": "Tables of Contents", - "landing.layout.p2.desc": "TOC entries, page numbers and cross-references updated correctly.", - "landing.layout.p3.title": "Charts & Graphs", - "landing.layout.p3.desc": "Titles, axis labels, legends and series names — everything is translated.", - "landing.layout.p4.title": "Shapes & Text Boxes", - "landing.layout.p4.desc": "Rectangles, rounded blocks, callouts — localized everywhere.", - "landing.layout.p5.title": "Headers & Footers", - "landing.layout.p5.desc": "Headers, footers and footnotes are never missed.", - "landing.layout.p6.title": "130+ Languages", - "landing.layout.p6.desc": "Google Translate, DeepL and professional-grade AI engines.", - "landing.formats.title": "Every format,", - "landing.formats.title2": "every element", - "landing.formats.subtitle": "We translate what others miss. Your business deserves irreproachable documentation.", - "landing.formats.word.name": "Word", - "landing.formats.word.i1": "Paragraphs & headings", - "landing.formats.word.i2": "Tables & charts", - "landing.formats.word.i3": "SmartArt diagrams", - "landing.formats.word.i4": "Table of contents", - "landing.formats.word.i5": "Headers & footers", - "landing.formats.word.i6": "Shapes & text boxes", - "landing.formats.word.i7": "Footnotes & endnotes", - "landing.formats.excel.name": "Excel", - "landing.formats.excel.i1": "Cell values", - "landing.formats.excel.i2": "Sheet names", - "landing.formats.excel.i3": "Charts & labels", - "landing.formats.excel.i4": "Headers & footers", - "landing.formats.excel.i5": "Merged cells preserved", - "landing.formats.pptx.name": "PowerPoint", - "landing.formats.pptx.i1": "Slide text & notes", - "landing.formats.pptx.i2": "Charts & diagrams", - "landing.formats.pptx.i3": "Shapes & text boxes", - "landing.formats.pptx.i4": "Master layouts", - "landing.formats.pptx.i5": "Animations preserved", - "landing.formats.pdf.name": "PDF", - "landing.formats.pdf.i1": "Text-based PDFs", - "landing.formats.pdf.i2": "Layout preserved", - "landing.formats.pdf.i3": "Images kept in place", - "landing.formats.pdf.i4": "Tables maintained", - "landing.formats.pdf.i5": "Output as DOCX or PDF", - "landing.pricing.title": "Simple, honest pricing", - "landing.pricing.subtitle": "What you see is what you pay. No hidden fees.", - "landing.pricing.monthly": "Monthly", - "landing.pricing.annual": "Annual", - "landing.pricing.bestValue": "Most Popular", - "landing.pricing.month": "/month", - "landing.pricing.footer": "The displayed price is the price you pay. No hidden fees after translation.", - "landing.pricing.starter.name": "Starter", - "landing.pricing.starter.desc": "For individuals and small projects", - "landing.pricing.starter.f1": "50 documents / month", - "landing.pricing.starter.f2": "Up to 50 pages per doc", - "landing.pricing.starter.f3": "Google Translate + DeepL", - "landing.pricing.starter.f4": "Files up to 10 MB", - "landing.pricing.starter.cta": "Get Started", - "landing.pricing.pro.name": "Pro", - "landing.pricing.pro.desc": "For demanding professionals", - "landing.pricing.pro.f1": "200 documents / month", - "landing.pricing.pro.f2": "Up to 200 pages per doc", - "landing.pricing.pro.f3": "AI-powered translation", - "landing.pricing.pro.f4": "Google + DeepL included", - "landing.pricing.pro.f5": "Custom glossaries & prompts", - "landing.pricing.pro.f6": "Priority support", - "landing.pricing.pro.cta": "Try Pro", - "landing.pricing.business.name": "Business", - "landing.pricing.business.desc": "For teams with high-volume needs", - "landing.pricing.business.f1": "1,000 documents / month", - "landing.pricing.business.f2": "Up to 500 pages per doc", - "landing.pricing.business.f3": "Premium AI (Claude)", - "landing.pricing.business.f4": "All providers + API access", - "landing.pricing.business.f5": "Webhooks & automation", - "landing.pricing.business.f6": "5 team seats", - "landing.pricing.business.cta": "Contact Us", - "landing.pricing.free.name": "Free", - "landing.pricing.free.desc": "Perfect to discover the app", - "landing.pricing.free.cta": "Choose this plan", - "landing.pricing.enterprise.name": "Enterprise", - "landing.pricing.enterprise.desc": "Custom solutions for large organizations", - "landing.pricing.enterprise.cta": "Contact us", - "landing.cta.title": "Start translating in 30 seconds", - "landing.cta.subtitle": "No credit card required. Try for free now and bring your multilingual documents back to life.", - "landing.cta.button": "Create Free Account", - "landing.cta.secure": "Secured by AES-256 encryption", - "landing.footer.desc": "Expert in intelligent document translation. We blend the art of layout with the science of contextual AI.", - "landing.footer.product": "Product", - "landing.footer.resources": "Resources", - "landing.footer.legal": "Legal", - "landing.footer.rights": "© 2026 Wordly.art — All rights reserved.", - "dashboard.translate.pageTitle": "Translate a document", - "dashboard.translate.pageSubtitle": - "Import a file and choose the target language", - "dashboard.translate.errorNotificationTitle": "Error", - "dashboard.translate.dropzone.uploadAria": "File drop zone", - "dashboard.translate.dropzone.title": "Drag & drop your file here", - "dashboard.translate.dropzone.subtitle": - "or click to select (DOCX, XLSX, PPTX, PDF)", - "dashboard.translate.dropzone.replaceFile": "Replace file", - "dashboard.translate.language.source": "Source language", - "dashboard.translate.language.target": "Target language", - "dashboard.translate.language.loading": "Loading languages…", - "dashboard.translate.language.autoDetect": "Auto-detect", - "dashboard.translate.language.selectPlaceholder": "Select…", - "dashboard.translate.language.loadErrorPrefix": - "Failed to load languages", - "dashboard.translate.provider.loading": "Loading providers…", - "dashboard.translate.provider.noneConfigured": "No providers configured", - "dashboard.translate.provider.modelTitle": "Model", - "dashboard.translate.provider.sectionTitle": "Provider", - "dashboard.translate.provider.llmDivider": "AI · Context-Aware", - "dashboard.translate.provider.llmDividerPro": - "AI · Context-Aware (Pro)", - "dashboard.translate.provider.upgrade": "Upgrade to Pro", - "dashboard.translate.provider.upgradeSuffix": - "to unlock AI translation", - "dashboard.translate.provider.tabStandard": "Standard", - "dashboard.translate.provider.tabLLM": "AI Multi-Models", - "translate.glossary.selectGlossary": "Select a glossary...", - "dashboard.translate.translateImages": "Translate images", - "dashboard.translate.translateImagesDesc": "Extract and translate text inside images (vision required)", - "dashboard.translate.trust.zeroRetention": "Zero retention", - "dashboard.translate.trust.deletedAfter": - "Files deleted after processing", - "dashboard.translate.actions.uploading": "Uploading…", - "dashboard.translate.actions.translate": "Translate", - "dashboard.translate.actions.filePrefix": "File: ", - "dashboard.translate.actions.cancel": "Cancel", - "dashboard.translate.actions.tryAgain": "Try Again", - "dashboard.translate.steps.uploading": "Uploading file…", - "dashboard.translate.steps.starting": "Starting translation…", - "dashboard.translate.complete.title": "Translation complete!", - "dashboard.translate.complete.descNamed": - "Your file {name} has been translated successfully.", - "dashboard.translate.complete.descGeneric": - "Your file has been translated successfully.", - "dashboard.translate.complete.downloading": "Downloading…", - "dashboard.translate.complete.download": "Download", - "dashboard.translate.complete.newTranslation": "New Translation", - "dashboard.translate.complete.toastOkTitle": "Success", - "dashboard.translate.complete.toastOkDesc": "{name} has been downloaded successfully.", - "dashboard.translate.complete.toastFailTitle": "Failed", - "dashboard.translate.complete.toastFailDesc": - "Translation failed. Please try again.", - "dashboard.translate.sourceDocument": "Source Document", - "dashboard.translate.configuration": "Configuration", - "dashboard.translate.translating": "Translation in progress", - "dashboard.translate.liveMonitor": "Live Monitor", - "dashboard.translate.summary": "Summary", - "dashboard.translate.engine": "Engine", - "dashboard.translate.confidence": "Confidence", - "dashboard.translate.cancel": "Cancel", - "dashboard.translate.segments": "Segments", - "dashboard.translate.characters": "Characters", - "dashboard.translate.elapsed": "Elapsed", - "dashboard.translate.segPerMin": "Seg/min", - "dashboard.translate.highQuality": "High quality", - "dashboard.translate.quality": "Quality", - "dashboard.translate.completed": "Translation complete", - "dashboard.translate.replace": "Replace", - "dashboard.translate.pdfMode.title": "PDF Translation Mode", - "dashboard.translate.pdfMode.preserveLayout": "Preserve Layout", - "dashboard.translate.pdfMode.textOnly": "Text Only", - "dashboard.translate.pdfMode.preserveLayoutDesc": "Keeps images, tables & formatting. Best for simple PDFs.", - "dashboard.translate.pdfMode.textOnlyDesc": "Translates all text perfectly. Clean output, no layout issues.", - "dashboard.translate.pipeline.upload": "Upload", - "dashboard.translate.pipeline.analyze": "Analyze", - "dashboard.translate.pipeline.translate": "Translation", - "dashboard.translate.pipeline.rebuild": "Rebuild", - "dashboard.translate.pipeline.finalize": "Finalize", - "dashboard.translate.progress.processingFallback": "Processing…", - "dashboard.translate.progress.connectionLost": "Connection lost. Retrying…", - "dashboard.translate.progress.failedTitle": "Translation failed", - "dashboard.translate.error.unexpected": "An unexpected error occurred. Please try again.", - "dashboard.translate.error.noResult": "Translation produced no results. Verify the document contains text, then try again or choose another engine.", - "dashboard.translate.error.apiKey": "Invalid or missing API key. Contact the administrator to configure API keys.", - "dashboard.translate.error.quota": "Usage limit reached. Try again in a few minutes or choose another engine.", - "dashboard.translate.error.timeout": "Connection to the translation service timed out. Check your network and try again.", - "dashboard.translate.error.sessionExpired": "Session expired. Click Retry to restart the translation.", - "dashboard.translate.error.empty": "The document appears empty or contains no translatable text (scanned PDF image?).", - "dashboard.translate.error.unsupported": "Unsupported file format or corrupted file.", - "dashboard.translate.error.connection": "Connection lost. Check your network and try again.", - "dashboard.translate.error.generic": "Translation failed: {detail}", - "dashboard.translate.error.title": "Translation failed", - "dashboard.translate.retry": "Retry translation", - "dashboard.translate.newFile": "New file", - "dashboard.translate.modeAI": "AI Mode", - "dashboard.translate.modeClassic": "Classic Mode", - "dashboard.translate.glossaryLLMHint": "Glossaries available in AI mode", - "dashboard.translate.submitting": "Submitting...", - "dashboard.translate.submit": "Start translation", - "dashboard.translate.noFile": "Upload a file first", - "dashboard.translate.noTargetLang": "Select a target language", - "glossaries.yourGlossaries": "Your glossaries", - "glossaries.title": "Glossaries & Context", - "glossaries.description": "Manage your glossaries and context instructions for more accurate translations.", - "glossaries.createNew": "Create new", - "glossaries.empty": "No glossaries yet", - "glossaries.emptyDesc": "Create your first glossary or load a professional preset above", - "glossaries.defineTerms": "terms", - "glossaries.aboutTitle": "About glossaries", - "glossaries.aboutDesc": "Glossaries let you define exact translations for specific terms. When you translate a document, the glossary terms are used to ensure consistent and accurate translations.", - "glossaries.aboutFormat": "Each term has a source word and translations in multiple languages. Select a glossary in the translation page to apply it.", - "glossaries.toast.created": "Glossary created", - "glossaries.toast.createdDesc": "The glossary \"{name}\" has been created.", - "glossaries.toast.imported": "Glossary imported", - "glossaries.toast.importedDesc": "The glossary \"{name}\" has been imported.", - "glossaries.toast.updated": "Glossary updated", - "glossaries.toast.updatedDesc": "The glossary \"{name}\" has been updated.", - "glossaries.toast.deleted": "Glossary deleted", - "glossaries.toast.deletedDesc": "The glossary has been deleted.", - "glossaries.toast.error": "Error", - "glossaries.toast.errorCreate": "Failed to create glossary", - "glossaries.toast.errorImport": "Failed to import glossary", - "glossaries.toast.errorUpdate": "Failed to update glossary", - "glossaries.toast.errorDelete": "Failed to delete glossary", - "glossaries.dialog.title": "New glossary", - "glossaries.dialog.description": "Create a glossary for your translations", - "glossaries.dialog.nameLabel": "Name", - "glossaries.dialog.namePlaceholder": "My glossary", - "glossaries.dialog.tabTemplates": "Templates", - "glossaries.dialog.tabFile": "File", - "glossaries.dialog.tabManual": "Manual", - "glossaries.dialog.cancel": "Cancel", - "glossaries.dialog.creating": "Creating…", - "glossaries.dialog.importing": "Importing…", - "glossaries.dialog.importBtn": "Import", - "glossaries.dialog.selectPrompt": "Select", - "glossaries.dialog.createBtn": "Create", - "glossaries.dialog.createEmpty": "Create empty", - "glossaries.dialog.terms": "terms", - "glossaries.dialog.templatesDesc": "Choose a predefined template", - "glossaries.dialog.templatesEmpty": "No templates available", - "glossaries.dialog.dropTitle": "Drag a CSV file here", - "glossaries.dialog.dropOr": "or", - "glossaries.dialog.dropFormats": "CSV, TSV, TXT", - "glossaries.termEditor.addTerm": "Add Term", - "glossaries.termEditor.maxReached": "Maximum {max} terms per glossary reached.", - "glossaries.dialog.formatTitle": "Format", - "glossaries.dialog.formatDesc": "source,target (one per line)", - "glossaries.dialog.formatNote": "First line skipped if header detected", - "glossaries.dialog.errorFormat": "Unsupported format", - "glossaries.dialog.errorSize": "File too large", - "glossaries.dialog.errorEmpty": "Empty file", - "glossaries.dialog.errorRead": "Read error", - "glossaries.dialog.parsing": "Parsing…", - "glossaries.dialog.termsImported": "terms imported", - "glossaries.dialog.changeFile": "Change file", - "glossaries.dialog.retry": "Retry", - "glossaries.edit.title": "Edit Glossary", - "glossaries.edit.description": "Update the glossary name, language pair, and terms.", - "glossaries.edit.nameLabel": "Glossary Name", - "glossaries.edit.namePlaceholder": "Enter glossary name...", - "glossaries.edit.sourceLang": "Source language", - "glossaries.edit.targetLang": "Target language", - "glossaries.edit.termsLabel": "Terms ({count} valid)", - "glossaries.edit.exportCsv": "Export CSV", - "glossaries.edit.importCsv": "Import CSV", - "glossaries.edit.cancel": "Cancel", - "glossaries.edit.saving": "Saving...", - "glossaries.edit.saveChanges": "Save Changes", - "glossaries.edit.importFailedTitle": "Import failed", - "glossaries.edit.importFailedMaxDesc": "CSV contains {count} terms, but maximum is {max}. Please reduce the number of terms.", - "glossaries.edit.importSuccessTitle": "Import successful", - "glossaries.edit.importSuccessDesc": "{count} terms imported successfully.", - "glossaries.edit.importFailedEmptyDesc": "No valid terms found in CSV file.", - "glossaries.edit.importFailedReadDesc": "Failed to read CSV file.", - "glossaries.delete.title": "Delete Glossary", - "glossaries.delete.description": "Are you sure you want to delete this glossary?", - "glossaries.delete.warning": "This action cannot be undone", - "glossaries.delete.warningDesc": "All term pairs will be permanently removed.", - "glossaries.delete.cancel": "Cancel", - "glossaries.delete.deleting": "Deleting...", - "glossaries.delete.deleteBtn": "Delete", - "glossaries.upgrade.title": "Glossaries", - "glossaries.upgrade.description": "Customize your translations with custom terminology", - "glossaries.upgrade.feature1": "Create multiple glossaries", - "glossaries.upgrade.feature2": "Define source→target term pairs", - "glossaries.upgrade.feature3": "Import/export via CSV", - "glossaries.upgrade.feature4": "Apply to LLM translations", - "glossaries.upgrade.proFeatureBefore": "Glossaries are a ", - "glossaries.upgrade.proFeatureAfter": " feature. Upgrade to unlock custom terminology.", - "glossaries.upgrade.proLabel": "Pro", - "glossaries.upgrade.upgradeBtn": "Upgrade to Pro", - "glossaries.loading": "Loading...", - "glossaries.howItWorks.title": "How these settings are used", - "glossaries.howItWorks.step1Title": "Configure here", - "glossaries.howItWorks.step1Desc": "Write your context instructions or create/import a glossary of terms.", - "glossaries.howItWorks.step2Title": "Activate in Translate", - "glossaries.howItWorks.step2Desc": "On the translation page, in the right column, select your glossary.", - "glossaries.howItWorks.warning": "Context instructions apply automatically to all your AI translations once saved. Glossaries must be manually selected on the Translate page.", - "glossaries.howItWorks.goToTranslate": "Go to Translate", - "glossaries.status.unsaved": "Unsaved", - "glossaries.status.active": "Active · applies to all AI translations", - "glossaries.status.inactive": "Inactive", - "glossaries.instructions.whatForBold": "What is it for?", - "glossaries.instructions.whatForDesc": "These instructions are automatically sent to the AI before each translation, without you having to do anything on the Translate page. Use them to guide the style, register or general terminology.", - "glossaries.instructions.example": "Example: \"You translate financial reports. Be formal, precise and keep all figures.\"", - "glossaries.instructions.charCount": "{count} characters", - "glossaries.instructions.emptyHint": "Empty — no instructions sent to the AI", - "glossaries.instructions.clearAll": "Clear all", - "glossaries.instructions.saving": "Saving...", - "glossaries.instructions.saved": "Saved", - "glossaries.presets.whatForBold": "What is it for?", - "glossaries.presets.whatForDesc": "Clicking a card creates a pre-filled glossary with domain-specific terms. This glossary will appear in your glossaries below, and you can manually select it on the Translate page to force precise term translations.", - "glossaries.presets.clickHint": "Click a card → glossary created → select it in Translate", - "glossaries.presets.creating": "Creating...", - "glossaries.presets.alreadyImported": "Imported", - "glossaries.presets.it.title": "IT / Software", - "glossaries.presets.it.desc": "Development, infrastructure, DevOps", - "glossaries.presets.legal.title": "Legal / Contracts", - "glossaries.presets.legal.desc": "Business law, litigation", - "glossaries.presets.medical.title": "Medical / Health", - "glossaries.presets.medical.desc": "Pharmacology, surgery, diagnosis", - "glossaries.presets.finance.title": "Finance / Accounting", - "glossaries.presets.finance.desc": "IFRS, balance sheets, taxation", - "glossaries.presets.marketing.title": "Marketing / Advertising", - "glossaries.presets.marketing.desc": "Digital, branding, analytics", - "glossaries.presets.hr.title": "HR / Human Resources", - "glossaries.presets.hr.desc": "Contracts, policies, recruitment", - "glossaries.presets.scientific.title": "Scientific / Research", - "glossaries.presets.scientific.desc": "Publications, theses, articles", - "glossaries.presets.ecommerce.title": "E-commerce / Sales", - "glossaries.presets.ecommerce.desc": "Online stores, catalogs, CRM", - "glossaries.grid.title": "Your", - "glossaries.grid.titleHighlight": "glossaries", - "glossaries.grid.countWithAction": "{count} glossary({plural}) — click a card to edit", - "glossaries.grid.emptyAction": "Create your first glossary or import a preset above", - "glossaries.grid.activeTranslation": "Active translation:", - "glossaries.grid.goToTranslate": "Go to Translate to activate", - "glossaries.badge.compatible": "Compatible", - "glossaries.badge.otherTarget": "Other target", - "glossaries.card.editTerms": "Edit terms", - "glossaries.card.created": "Created", - "glossaries.card.term": "term", - "glossaries.card.delete": "Delete", - "glossaries.grid.searchPlaceholder": "Search a glossary…", - "glossaries.grid.noResults": "No results for this search.", - "glossaries.detail.backToList": "Back to glossaries", - "glossaries.detail.save": "Save", - "glossaries.detail.savedTitle": "Saved", - "glossaries.detail.savedDesc": "The glossary has been updated.", - "glossaries.detail.settingsTitle": "Settings", - "glossaries.detail.sourceLang": "Source language", - "glossaries.detail.targetLang": "Target language", - "glossaries.detail.termsTitle": "Terms", - "glossaries.detail.terms": "terms", - "glossaries.detail.searchTerms": "Filter…", - "glossaries.detail.noTerms": "No terms yet.", - "glossaries.detail.addFirstTerm": "Add the first term", - "glossaries.detail.addTerm": "Add a term", - "glossaries.detail.maxReached": "Maximum limit reached", - "glossaries.detail.source": "Source", - "glossaries.detail.target": "Target", - "glossaries.detail.sourcePlaceholder": "source term", - "glossaries.detail.targetPlaceholder": "target term", - "glossaries.detail.csvTitle": "CSV", - "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", - "glossaries.detail.export": "Export", - "glossaries.detail.import": "Import", - "glossaries.detail.dangerTitle": "Danger zone", - "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", - "glossaries.detail.deleteGlossary": "Delete this glossary", - "glossaries.detail.confirmDelete": "Confirm deletion?", - "glossaries.detail.confirm": "Confirm", - "glossaries.detail.cancel": "Cancel", - "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", - "glossaries.detail.sourceLocked": "fixed", - "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", - "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", - "glossaries.detail.notFoundTitle": "Glossary not found", - "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", - "glossaries.detail.maxTermsTitle": "Limit reached", - "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", - "glossaries.detail.importEmptyTitle": "Empty file", - "glossaries.detail.importEmptyDesc": "No terms detected in this file.", - "glossaries.detail.importedTitle": "Imported", - "glossaries.detail.importedDesc": "{count} terms imported.", - "glossaries.detail.importErrorTitle": "Read error", - "glossaries.detail.importErrorDesc": "Unable to read the file.", - "apiKeys.webhook.title": "Webhook Integration", - "apiKeys.webhook.descriptionBefore": "Pass a ", - "apiKeys.webhook.descriptionAfter": " parameter to receive a POST request when your translation is complete.", - "apiKeys.webhook.codeParam": "webhook_url", - "translate.mode.label": "Translation Mode", - "translate.mode.classic": "Classic", - "translate.mode.classicDesc": "Fast", - "translate.mode.proLlm": "Pro LLM", - "translate.mode.proLlmDesc": "Context-Aware", - "translate.mode.tooltip": "Upgrade to Pro for LLM translation", - "translate.mode.upgradeLink": "Upgrade to Pro", - "translate.mode.upgradeDesc": "for LLM-powered translations", - - // ── Pricing page ── - "pricing.nav.back": "Back", - "pricing.nav.home": "Home", - "pricing.nav.mySubscription": "My Subscription", - - "pricing.header.badge": "AI Models Updated — March 2026", - "pricing.header.title": "A plan for every need", - "pricing.header.subtitle": "Translate your Word, Excel and PowerPoint documents while preserving the original layout. No API key required.", - "pricing.billing.monthly": "Monthly", - "pricing.billing.yearly": "Yearly", - - "pricing.plans.free.name": "Free", - "pricing.plans.starter.name": "Starter", - "pricing.plans.pro.name": "Pro", - "pricing.plans.business.name": "Business", - "pricing.plans.enterprise.name": "Enterprise", - - "pricing.plans.free.description": "Perfect for discovering the app", - "pricing.plans.starter.description": "For individuals and small projects", - "pricing.plans.pro.description": "For professionals and growing teams", - "pricing.plans.business.description": "For teams and organizations", - "pricing.plans.enterprise.description": "Custom solutions for large organizations", - - "pricing.plans.pro.highlight": "Most popular", - "pricing.plans.pro.badge": "POPULAR", - "pricing.plans.enterprise.badge": "ON REQUEST", - - "pricing.plans.free.feat1": "5 documents / month", - "pricing.plans.free.feat2": "Up to 15 pages per document", - "pricing.plans.free.feat3": "Google Translation included", - "pricing.plans.free.feat4": "All languages (130+)", - "pricing.plans.free.feat5": "Community support", - - "pricing.plans.starter.feat1": "50 documents / month", - "pricing.plans.starter.feat2": "Up to 50 pages per document", - "pricing.plans.starter.feat3": "Google Translation + DeepL", - "pricing.plans.starter.feat4": "Files up to 10 MB", - "pricing.plans.starter.feat5": "Email support", - "pricing.plans.starter.feat6": "30-day history", - - "pricing.plans.pro.feat1": "200 documents / month", - "pricing.plans.pro.feat2": "Up to 200 pages per document", - "pricing.plans.pro.feat3": "Essential AI Translation", - "pricing.plans.pro.feat4": "Google Translation + DeepL", - "pricing.plans.pro.feat5": "Files up to 25 MB", - "pricing.plans.pro.feat6": "Custom glossaries", - "pricing.plans.pro.feat7": "Priority support", - "pricing.plans.pro.feat8": "90-day history", - - "pricing.plans.business.feat1": "1,000 documents / month", - "pricing.plans.business.feat2": "Up to 500 pages per document", - "pricing.plans.business.feat3": "Essential + Premium AI (Claude Haiku)", - "pricing.plans.business.feat4": "All translation providers", - "pricing.plans.business.feat5": "Files up to 50 MB", - "pricing.plans.business.feat6": "API access (10,000 calls/month)", - "pricing.plans.business.feat7": "Notification webhooks", - "pricing.plans.business.feat8": "Dedicated support", - "pricing.plans.business.feat9": "1-year history", - "pricing.plans.business.feat10": "Advanced analytics", - - "pricing.plans.enterprise.feat1": "Unlimited documents", - "pricing.plans.enterprise.feat2": "All AI models (GPT-5, Claude Opus 4.6…)", - "pricing.plans.enterprise.feat3": "On-premise or dedicated cloud deployment", - "pricing.plans.enterprise.feat4": "99.9% SLA guaranteed", - "pricing.plans.enterprise.feat5": "24/7 dedicated support", - "pricing.plans.enterprise.feat6": "White-label", - "pricing.plans.enterprise.feat7": "Unlimited teams", - "pricing.plans.enterprise.feat8": "Custom integrations", - - "pricing.card.onRequest": "On request", - "pricing.card.free": "Free", - "pricing.card.perMonth": "/month", - "pricing.card.billedYearly": "Billed {price} € / year", - "pricing.card.documents": "Documents", - "pricing.card.pagesMax": "Max pages", - "pricing.card.aiTranslation": "AI Translation", - "pricing.card.unlimited": "Unlimited", - "pricing.card.perMonthStat": "/ month", - "pricing.card.perDoc": "p / doc", - "pricing.card.aiEssential": "Essential", - "pricing.card.aiEssentialPremium": "Essential + Premium", - "pricing.card.aiCustom": "Custom", - "pricing.card.myPlan": "My Plan", - "pricing.card.managePlan": "Manage my plan", - "pricing.card.startFree": "Start for free", - "pricing.card.contactUs": "Contact us", - "pricing.card.choosePlan": "Choose this plan", - "pricing.card.processing": "Processing…", - - "pricing.comparison.title": "Detailed comparison", - "pricing.comparison.subtitle": "Everything included in each plan", - "pricing.comparison.feature": "Feature", - "pricing.comparison.docsPerMonth": "Documents / month", - "pricing.comparison.pagesMaxPerDoc": "Max pages / document", - "pricing.comparison.maxFileSize": "Max file size", - "pricing.comparison.googleTranslation": "Google Translation", - "pricing.comparison.deepl": "DeepL", - "pricing.comparison.aiEssential": "Essential AI Translation", - "pricing.comparison.aiPremium": "Premium AI Translation", - "pricing.comparison.apiAccess": "API Access", - "pricing.comparison.priorityProcessing": "Priority processing", - "pricing.comparison.support": "Support", - "pricing.comparison.support.community": "Community", - "pricing.comparison.support.email": "Email", - "pricing.comparison.support.priority": "Priority", - "pricing.comparison.support.dedicated": "Dedicated", - "pricing.comparison.mb": "MB", - - "pricing.credits.title": "Additional credits", - "pricing.credits.subtitle": "Need more? Buy credits individually, no subscription.", - "pricing.credits.perPage": "1 credit = 1 translated page.", - "pricing.credits.bestValue": "Best value", - "pricing.credits.unit": "credits", - "pricing.credits.centsPerCredit": "cts / credit", - "pricing.credits.buy": "Buy", - - "pricing.trust.encryption.title": "End-to-end encryption", - "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 at rest", - "pricing.trust.languages.title": "130+ languages", - "pricing.trust.languages.sub": "Including Arabic, Persian, Hebrew (RTL)", - "pricing.trust.parallel.title": "Parallel processing", - "pricing.trust.parallel.sub": "Ultra-fast multi-threaded AI", - "pricing.trust.availability.title": "Available 24/7", - "pricing.trust.availability.sub": "99.9% guaranteed uptime", - - "pricing.aiModels.title": "Our AI Models — March 2026", - "pricing.aiModels.essential.title": "Essential AI Translation", - "pricing.aiModels.essential.plan": "Pro Plan", - "pricing.aiModels.essential.descPrefix": "Based on", - "pricing.aiModels.essential.descSuffix": "— the most cost-effective AI model of 2026. Quality comparable to frontier models at a fraction of the cost.", - "pricing.aiModels.essential.modelName": "our Essential AI model", - "pricing.aiModels.essential.context": "163K tokens of context", - "pricing.aiModels.essential.value": "Excellent value for money", - "pricing.aiModels.premium.title": "Premium AI Translation", - "pricing.aiModels.premium.plan": "Business Plan", - "pricing.aiModels.premium.descPrefix": "Based on", - "pricing.aiModels.premium.descSuffix": "by Anthropic — accurate on legal, medical and complex technical documents.", - "pricing.aiModels.premium.context": "200K tokens of context", - "pricing.aiModels.premium.precision": "Best accuracy", - - "pricing.faq.title": "Frequently asked questions", - "pricing.faq.q1": "Can I change plans at any time?", - "pricing.faq.a1": "Yes. Upgrading is immediate and prorated. Downgrading takes effect at the end of the current period.", - "pricing.faq.q2": "What is \"Essential AI Translation\"?", - "pricing.faq.a2": "It's our AI engine. It understands your documents' context, preserves layout and handles technical terms much better than classic translation.", - "pricing.faq.q3": "What's the difference between Essential and Premium AI?", - "pricing.faq.a3": "Essential AI uses an optimized model (excellent value for money). Premium AI uses Anthropic's Claude Sonnet 4.6, more accurate on legal, medical and complex technical documents.", - "pricing.faq.q4": "Are my documents kept after translation?", - "pricing.faq.a4": "Translated files are available according to your plan (30 days Starter, 90 days Pro, 1 year Business). They are encrypted at rest and in transit.", - "pricing.faq.q5": "What happens if I exceed my monthly quota?", - "pricing.faq.a5": "You can buy additional credits individually, or upgrade your plan. You are notified at 80% usage.", - "pricing.faq.q6": "Is there a free trial for paid plans?", - "pricing.faq.a6": "The Free plan is permanent and requires no credit card. For Pro and Business plans, contact us for a 14-day trial.", - "pricing.faq.q7": "What file formats are supported?", - "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx), and soon PDF. All plans support the same formats.", - - "pricing.cta.title": "Ready to start?", - "pricing.cta.subtitle": "Start for free, no credit card required. Upgrade when you need to.", - "pricing.cta.createAccount": "Create a free account", - "pricing.cta.login": "Sign in", - - "pricing.toast.demo": "Demo mode — Stripe is not yet configured. In production, you would be redirected to payment to activate the {planId} plan.", - "pricing.toast.networkError": "Network error. Please try again.", - "pricing.toast.paymentError": "Error creating payment.", - - // ── Register page ── - "register.title": "Create an account", - "register.subtitle": "Start translating for free", - "register.error.failed": "Registration failed", - - "register.name.label": "Name", - "register.name.placeholder": "Your name", - "register.name.error": "Name must be at least 2 characters", - - "register.email.label": "Email address", - "register.email.placeholder": "you@example.com", - "register.email.error": "Invalid email address", - - "register.password.label": "Password", - "register.password.error": "Password must be at least 8 characters with an uppercase, a lowercase and a digit", - "register.password.show": "Show password", - "register.password.hide": "Hide password", - "register.password.strengthLabel": "Strength:", - "register.password.strength.weak": "Weak", - "register.password.strength.medium": "Medium", - "register.password.strength.strong": "Strong", - - "register.confirmPassword.label": "Confirm password", - "register.confirmPassword.error": "Passwords do not match", - "register.confirmPassword.show": "Show", - "register.confirmPassword.hide": "Hide", - - "register.submit.creating": "Creating account...", - "register.submit.create": "Create my account", - - "register.hasAccount": "Already have an account?", - "register.login": "Sign in", - - "register.terms.prefix": "By creating an account, you accept our", - "register.terms.link": "terms of service", - - "login.errorTitle": "Login Error", - "login.welcomeBack": "Welcome back", - "login.signInToContinue": "Sign in to continue translating", - "login.email": "Email", - "login.emailPlaceholder": "you@example.com", - "login.password": "Password", - "login.forgotPassword": "Forgot password?", - "login.passwordPlaceholder": "••••••••", - "login.signingIn": "Signing in...", - "login.signIn": "Sign In", - "login.noAccount": "Don't have an account?", - "login.signUpFree": "Sign up for free", - "login.orContinueWith": "or continue with email", - "login.google.connecting": "Connecting…", - "login.google.errorGeneric": "Something went wrong with Google sign-in.", - "login.google.errorFailed": "Google sign-in failed. Please try again.", - "forgotPassword.enterEmail": "Please enter your email address", - "forgotPassword.error": "An error occurred", - "forgotPassword.title": "Forgot Password", - "forgotPassword.checkEmail": "Check your inbox", - "forgotPassword.subtitle": "Enter your email to receive a reset link", - "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", - "forgotPassword.emailLabel": "Email address", - "forgotPassword.emailPlaceholder": "you@example.com", - "forgotPassword.sending": "Sending...", - "forgotPassword.sendLink": "Send reset link", - "forgotPassword.backToLogin": "Back to login", - "forgotPassword.loading": "Loading...", - "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", - "resetPassword.passwordMismatch": "Passwords do not match", - "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", - "resetPassword.error": "An error occurred", - "resetPassword.invalidLink": "Invalid link", - "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", - "resetPassword.requestNewLink": "Request new link", - "resetPassword.successTitle": "Password reset", - "resetPassword.newPasswordTitle": "New password", - "resetPassword.successSubtitle": "You will be redirected to login", - "resetPassword.subtitle": "Set your new password", - "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", - "resetPassword.newPassword": "New password", - "resetPassword.showPassword": "Show password", - "resetPassword.hidePassword": "Hide password", - "resetPassword.confirmPassword": "Confirm password", - "resetPassword.resetting": "Resetting...", - "resetPassword.resetPassword": "Reset password", - "resetPassword.backToLogin": "Back to login", - "resetPassword.loading": "Loading...", - - // ── Common ── - "common.loading": "Loading...", - - // ── Profile ── - "profile.header.title": "My Profile", - "profile.header.subtitle": "Manage your account and preferences.", - "profile.tabs.account": "Account", - "profile.tabs.subscription": "Subscription", - "profile.tabs.preferences": "Preferences", - "profile.account.user": "User", - "profile.account.memberSince": "Member since", - "profile.plan.label": "Plan", - "profile.plan.free": "Free", - "profile.plan.starter": "Starter", - "profile.plan.pro": "Pro", - "profile.plan.business": "Business", - "profile.plan.enterprise": "Enterprise", - "profile.plan.pricePerMonth": "{price} €/month", - "profile.subscription.canceling": "Canceling", - "profile.subscription.active": "Active", - "profile.subscription.unknown": "Unknown", - "profile.subscription.accessUntil": "Access until", - "profile.subscription.renewalOn": "Renewal on", - "profile.subscription.upgradePlan": "Upgrade to a paid plan", - "profile.subscription.changePlan": "Change plan", - "profile.subscription.manageBilling": "Manage billing", - "profile.subscription.billingUnavailable": "Billing portal unavailable.", - "profile.subscription.billingError": "Error accessing billing portal.", - "profile.subscription.cancelSuccess": "Subscription canceled. You keep access until the end of the period.", - "profile.subscription.cancelError": "Error during cancellation.", - "profile.subscription.networkError": "Network error.", - "profile.usage.title": "Usage this month", - "profile.usage.resetOn": "Reset on", - "profile.usage.documents": "Documents", - "profile.usage.pages": "Pages", - "profile.usage.extraCredits": "extra credit", - "profile.usage.extraCreditsPlural": "extra credits", - "profile.usage.quotaReached": "Quota reached", - "profile.usage.quotaReachedDesc": "Upgrade to a higher plan to continue.", - "profile.usage.unlockMore": "Unlock more translations with a paid plan.", - "profile.usage.viewPlans": "View plans", - "profile.usage.includedInPlan": "Included in your plan", - "profile.danger.title": "Danger zone", - "profile.danger.description": "Cancellation takes effect at the end of your current period. You keep access until that date.", - "profile.danger.confirm": "Are you sure? This action cannot be undone.", - "profile.danger.confirmCancel": "Confirm cancellation", - "profile.danger.cancelSubscription": "Cancel my subscription", - "profile.danger.keep": "No, keep", - "profile.prefs.interfaceLang": "Interface language", - "profile.prefs.interfaceLangDesc": "The language is automatically detected based on your browser. You can change it manually.", - "profile.prefs.defaultTargetLang": "Default target language", - "profile.prefs.selectLanguage": "Select a language", - "profile.prefs.defaultTargetLangDesc": "This language will be pre-selected for your translations.", - "profile.prefs.save": "Save", - "profile.prefs.theme": "Theme", - "profile.prefs.themeDesc": "Choose the interface appearance", - "profile.prefs.cache": "Cache", - "profile.prefs.cacheDesc": "Clearing the local cache can fix some display issues.", - "profile.prefs.clearing": "Clearing...", - "profile.prefs.clearCache": "Clear cache", - - // ── Settings ── - "settings.title": "Settings", - "settings.subtitle": "General application configuration", - "settings.formats.title": "Supported formats", - "settings.formats.subtitle": "Document types you can translate", - "settings.formats.formulas": "Formulas", - "settings.formats.styles": "Styles", - "settings.formats.images": "Images", - "settings.formats.headers": "Headers", - "settings.formats.tables": "Tables", - "settings.formats.slides": "Slides", - "settings.formats.notes": "Notes", - "settings.cache.title": "Cache", - "settings.cache.desc": "Clearing the local cache can fix some display issues.", - "settings.cache.clearing": "Clearing...", - "settings.cache.clear": "Clear cache", - - // ── Services ── - "services.title": "Translation Providers", - "services.subtitle": "Providers are configured by the administrator. You can see which ones are currently available for your account.", - "services.loading": "Loading providers...", - "services.noProviders": "No providers are currently configured. Contact your administrator.", - "services.classic": "Classic Translation", - "services.llmPro": "LLM · Context-Aware (Pro)", - "services.available": "Available", - "services.model": "Model", - "services.adminOnly.title": "Provider configuration is admin-only", - "services.adminOnly.desc": "API keys, model selection, and provider activation are managed exclusively by the administrator in the admin panel. You never need to enter an API key.", - - // ── API Keys ── - "apiKeys.title": "API Keys", - "apiKeys.subtitle": "Manage your API keys for programmatic access to the translation API.", - "apiKeys.loading": "Loading...", - "apiKeys.sectionTitle": "API & Automation", - "apiKeys.sectionDesc": "Generate and manage your API keys for automation workflows", - "apiKeys.keysUsed": "{total} of {max} keys used", - "apiKeys.maxReached": "Maximum keys reached. Revoke a key to generate a new one.", - "apiKeys.canGenerate": "You can generate {count} more key", - "apiKeys.canGeneratePlural": "You can generate {count} more keys", - "apiKeys.generateNew": "Generate New Key", - "apiKeys.keyRevoked": "Key revoked", - "apiKeys.keyRevokedDesc": "The API key has been revoked successfully.", - "apiKeys.keyNotFound": "Key Not Found", - "apiKeys.keyNotFoundDesc": "The API key no longer exists. It may have already been revoked.", - "apiKeys.error": "Error", - "apiKeys.revokeError": "Failed to revoke the API key. Please try again.", - "apiKeys.limitReached": "Limit Reached", - "apiKeys.limitReachedDesc": "You have reached the maximum of 10 API keys. Revoke an existing key to generate a new one.", - "apiKeys.proRequired": "Pro Feature Required", - "apiKeys.proRequiredDesc": "API keys are a Pro feature. Please upgrade your account.", - "apiKeys.generateError": "Failed to generate API key. Please try again.", - "apiKeys.upgrade.title": "API Keys", - "apiKeys.upgrade.subtitle": "Automate your translations with API access", - "apiKeys.upgrade.feat1": "Generate unlimited API keys", - "apiKeys.upgrade.feat2": "Automate document translation", - "apiKeys.upgrade.feat3": "Webhook notifications", - "apiKeys.upgrade.feat4": "LLM translation modes", - "apiKeys.upgrade.proFeature": "API Keys are a {pro} feature. Upgrade to unlock API automation.", - "apiKeys.upgrade.pro": "Pro", - "apiKeys.upgrade.cta": "Upgrade to Pro", - "apiKeys.dialog.maxTitle": "Maximum Keys Reached", - "apiKeys.dialog.maxDesc": "You have reached the maximum of 10 API keys. Please revoke an existing key before generating a new one.", - "apiKeys.dialog.close": "Close", - "apiKeys.dialog.generated": "API Key Generated!", - "apiKeys.dialog.generatedDesc": "Your new API key has been created. Copy it now - it won't be shown again.", - "apiKeys.dialog.important": "Important:", - "apiKeys.dialog.importantDesc": "This is the only time you'll see this key. Store it securely.", - "apiKeys.dialog.apiKey": "API Key", - "apiKeys.dialog.name": "Name:", - "apiKeys.dialog.done": "Done", - "apiKeys.dialog.copied": "I've copied the key", - "apiKeys.dialog.generateTitle": "Generate New API Key", - "apiKeys.dialog.generateDesc": "Create a new API key for programmatic access to the translation API.", - "apiKeys.dialog.keyName": "Key Name (optional)", - "apiKeys.dialog.keyNamePlaceholder": "e.g., Production, Staging", - "apiKeys.dialog.keyNameHint": "A descriptive name to help you identify this key later.", - "apiKeys.dialog.nameTooLong": "Name must be {max} characters or less", - "apiKeys.dialog.nameInvalid": "Name can only contain letters, numbers, spaces, hyphens, and underscores", - "apiKeys.dialog.cancel": "Cancel", - "apiKeys.dialog.generating": "Generating...", - "apiKeys.dialog.generate": "Generate Key", - "apiKeys.table.name": "Name", - "apiKeys.table.prefix": "Prefix", - "apiKeys.table.created": "Created", - "apiKeys.table.lastUsed": "Last used", - "apiKeys.table.never": "Never", - "apiKeys.table.actions": "Actions", - "apiKeys.table.revoke": "Revoke", - "apiKeys.table.copyPrefix": "Copy key prefix", - "apiKeys.table.revokeKey": "Revoke key", - "apiKeys.revokeDialog.title": "Revoke API Key", - "apiKeys.revokeDialog.desc": "Are you sure you want to revoke the key \"{name}\"? This action cannot be undone.", - "apiKeys.revokeDialog.confirm": "Yes, revoke", - "apiKeys.revokeDialog.cancel": "Cancel", - - // ── Context & Glossary ── - "context.proTitle": "Pro Feature", - "context.proDesc": "Context and professional glossaries are available with Pro, Business and Enterprise plans. They provide more accurate translations through instructions and vocabulary specific to your domain.", - "context.viewPlans": "View plans", - "context.title": "Context & Glossary", - "context.subtitle": "Improve translation quality with instructions and vocabulary specific to your domain.", - "context.presets.title": "Professional glossaries", - "context.presets.desc": "Load a complete glossary with instructions and specialized terminology", - "context.instructions.title": "Context instructions", - "context.instructions.desc": "Instructions the AI will follow during translation", - "context.instructions.placeholder": "E.g.: You translate HVAC technical documents. Use precise engineering terminology...", - "context.glossary.title": "Technical glossary", - "context.glossary.desc": "Format: source=target (one per line). Glossaries loaded via preset are editable.", - "context.glossary.terms": "terms in the glossary", - "context.clearAll": "Clear all", - "context.saving": "Saving...", - "context.save": "Save", - "translate.glossary.title": "Glossary", - "translate.glossary.select": "Select a glossary", - "translate.glossary.none": "None", - "translate.glossary.terms": "terms", - "translate.glossary.proOnly": "Upgrade to Pro to use glossaries", - "translate.glossary.myGlossaries": "My glossaries", - "translate.glossary.fromTemplate": "Create from template", - "translate.glossary.noGlossaryForPair": "No glossary for", - "translate.glossary.noGlossaries": "No glossaries yet", - "translate.glossary.loading": "Loading...", - "translate.glossary.classicMode": "Neutral engine without glossary (AI only)", - "translate.glossary.selectPlaceholder": "Select a glossary...", - "translate.glossary.multilingual": "MULTILINGUAL", - "translate.glossary.noGlossaryAvailable": "No glossary available", - "translate.glossary.filterByLang": "Filter by language", - "translate.glossary.active": "Active", - "translate.glossary.inactive": "Inactive", - "translate.glossary.availableTemplates": "Available templates", - "translate.glossary.importing": "Importing...", - "translate.glossary.imported": "(Imported)", - "translate.glossary.noGlossaryForSource": "No glossary or template for source language", - "translate.glossary.createGlossary": "Create a glossary", - "translate.glossary.showAll": "Show all glossaries", - "translate.glossary.activePreview": "Active matches preview:", - "translate.glossary.total": "total", - "translate.glossary.moreTerms": "more terms", - "translate.glossary.noTerms": "No terms in this glossary.", - "translate.glossary.sourceTerm": "Source term", - "translate.glossary.translation": "Translation", - "translate.glossary.addTerm": "Add term", - "translate.glossary.disabledMode": "Neutral engine without glossary applied", - "translate.glossary.addTermError": "Error adding term", - "translate.glossary.networkError": "Network error", - "translate.glossary.importFailed": "Import failed ({status})", - "translate.glossary.helpText": "The glossary forces precise term translation. Choose a glossary whose source language matches your document's original language.", - "translate.glossary.sourceWarning": "Warning: This glossary uses source language", - "translate.glossary.sourceWarningBut": "but your document is configured in", - "translate.glossary.targetWarning": "Target mismatch: This glossary is designed to translate to", - "translate.glossary.targetWarningBut": "but your document targets", - "translate.glossary.targetWarningEnd": "Terms may not be relevant.", - "context.presets.createGlossary": "Create glossary", - "context.presets.created": "Glossary created", - "context.presets.createdDesc": "The glossary \"{name}\" has been created with {count} terms.", - "context.presets.hint": "Click a preset to create a glossary with domain-specific terms. Manage your glossaries in the Glossaries section.", - "context.glossary.manage": "Manage glossaries", - "context.saved": "Saved", - "context.savedDesc": "Your context instructions have been saved.", - - // ── Admin ── - "admin.login.title": "Administration", - "admin.login.required": "Login required", - "admin.login.password": "Admin password", - "admin.login.connecting": "Connecting...", - "admin.login.access": "Access admin panel", - "admin.login.restricted": "Restricted to administrators", - "admin.layout.checking": "Verifying authentication...", - "admin.dashboard.title": "Admin Dashboard", - "admin.dashboard.subtitle": "Administrator control panel", - "admin.dashboard.refresh": "Refresh", - "admin.dashboard.refreshTooltip": "Refresh dashboard data", - "admin.dashboard.config": "System Configuration", - "admin.dashboard.maxFileSize": "Max file size:", - "admin.dashboard.translationService": "Translation service:", - "admin.dashboard.formats": "Formats:", - "admin.nav.dashboard": "Dashboard", - "admin.nav.users": "Users", - "admin.nav.pricing": "Pricing & Stripe", - "admin.nav.providers": "Providers", - "admin.nav.system": "System", - "admin.nav.logs": "Logs", - "admin.users.title": "User Management", - "admin.users.subtitle": "View and manage user accounts", - "admin.users.planUpdated": "Plan updated", - "admin.users.planChanged": "The plan has been changed to \"{plan}\" successfully.", - "admin.users.unknownError": "Unknown error", - "admin.users.error": "Error", - "admin.users.planUpdateError": "Unable to update plan: {message}", - "admin.users.noKeys": "No keys", - "admin.users.noKeysDesc": "This user has no active API keys.", - "admin.users.keysRevoked": "Keys revoked", - "admin.users.keysRevokedDesc": "{count} API key(s) revoked successfully.", - "admin.users.revokeError": "Unable to revoke keys: {message}", - "admin.users.retry": "Retry", - "admin.system.title": "System", - "admin.system.subtitle": "Monitor system status and manage resources", - "admin.system.quotas": "Translation quotas", - "admin.system.resetQuotas": "Reset monthly quotas", - "admin.system.resetting": "Resetting...", - "admin.system.reset": "Reset", - "admin.system.allOperational": "All Systems Operational", - "admin.system.issuesDetected": "System Issues Detected", - "admin.system.waitingData": "Waiting for data...", - "admin.system.purging": "Purging...", - "admin.system.clean": "Clean", - "admin.system.purge": "Purge", - "memento.title": "Discover Momento", - "memento.slogan": "Momento is more than just a notes application. It's an intelligent ecosystem that connects, analyzes, and develops your ideas in real-time using 6 AI agents and cutting-edge semantic search.", - "memento.ctaFree": "Start for free", - "memento.ctaMore": "Learn more", - "common.backToHome": "Back to home", - "dashboard.topbar.interfaceLabel": "Translation Interface", - "dashboard.topbar.premiumAccess": "Premium Access", - "landing.hero.contextEngine": "Translation detected: Technical maintenance term for HVAC systems...", - "landing.hero.liveAnalysis": "Live Analysis", - "landing.hero.termsDetected": "terms detected", - "landing.steps.process": "PROCESS", - "landing.translate.newProject": "New Project", - "landing.translate.title": "Translate a document", - "landing.translate.subtitle": "Import a file and choose the target language", - "landing.translate.sourceDocument": "Source Document", - "landing.translate.configuration": "Configuration", - "landing.translate.sourceLang": "Source Language", - "landing.translate.targetLang": "Target Language", - "landing.translate.provider": "Provider", - "landing.translate.startTranslation": "Start Translation", - "landing.translate.zeroRetention": "Zero retention", - "landing.translate.filesDeleted": "Files deleted after processing", - "landing.translate.dropHere": "Drag & drop here", - "landing.translate.supportedFormats": "DOCX, XLSX, PPTX or PDF files supported", - "landing.translate.aiAnalysis": "Active AI Analysis", - "landing.translate.processing": "Processing", - "landing.translate.preservingLayout": "Your layout is being preserved", - "layout.nav.apiAccess": "API Access", - "layout.footer.terms": "Terms", - "layout.footer.privacy": "Privacy", - "fileUploader.uploadDocument": "Upload Document", - "fileUploader.uploadDesc": "Drag and drop or click to select a file (Excel, Word, PowerPoint)", - "fileUploader.dropHere": "Drop your file here...", - "fileUploader.dragAndDrop": "Drag & drop your document here", - "fileUploader.orClickBrowse": "or click to browse", - "fileUploader.preview": "Preview", - "fileUploader.translationOptions": "Translation Options", - "fileUploader.configureSettings": "Configure your translation settings", - "fileUploader.targetLanguage": "Target Language", - "fileUploader.selectLanguage": "Select language", - "fileUploader.translationProvider": "Translation Provider", - "fileUploader.selectProvider": "Select provider", - "fileUploader.advancedOptions": "Advanced Options", - "fileUploader.translateImages": "Translate Images", - "fileUploader.translating": "Translating...", - "fileUploader.translateDocument": "Translate Document", - "fileUploader.processing": "Processing...", - "fileUploader.translationError": "Translation Error", - "fileUploader.translationComplete": "Translation Complete!", - "fileUploader.translationCompleteDesc": "Your document has been translated successfully while preserving all formatting.", - "fileUploader.download": "Download Translated Document", - "fileUploader.webgpuUnsupported": "WebGPU is not supported in this browser. Please use Chrome 113+ or Edge 113+.", - "fileUploader.webllmNotLoaded": "WebLLM model not loaded. Go to Settings > Translation Services to load a model first.", - "fileUploader.extracting": "Extracting texts from document...", - "fileUploader.noTranslatable": "No translatable text found in document", - "fileUploader.foundTexts": "Found {count} texts to translate", - "fileUploader.translatingItem": "Translating {current}/{total}: \"{preview}\"", - "fileUploader.reconstructing": "Reconstructing document...", - "fileUploader.translatingLocally": "Translating locally with WebLLM...", - "checkout.activating": "Activating…", - "checkout.activatingDesc": "We are updating your subscription, please wait.", - "checkout.paymentConfirmed": "Payment confirmed!", - "checkout.subscriptionActivated": "Subscription activated!", - "checkout.planActivated": "{plan} plan activated!", - "checkout.redirectingToProfile": "Redirecting to your profile…", - "checkout.paymentReceived": "Payment received", - "checkout.redirecting": "Redirecting…", - "checkout.syncError": "Sync error", - "checkout.networkError": "Network error. Your payment is confirmed — please reload your profile.", - "dashboard.checkoutSyncError": "Error syncing payment.", - "dashboard.networkRefresh": "Network error. Please refresh the page.", - "dashboard.continueToTranslate": "Continue to translation", - "langSelector.search": "Search...", - "langSelector.noResults": "No results", - "langSelector.source": "Source", - "langSelector.target": "Target", - "langSelector.swap": "Swap", - "translateComplete.highQuality": "High quality", - "translateComplete.segments": "Segments", - "translateComplete.characters": "Characters", - "translateComplete.confidence": "Confidence", - "providerTheme.deepseek.badge": "Essential", - "providerTheme.deepseek.subBadge": "Technical & Eco", - "providerTheme.deepseek.desc": "Ultra-precise and economical translation, ideal for technical documents and code.", - "providerTheme.openai.badge": "Premium", - "providerTheme.openai.subBadge": "High fidelity", - "providerTheme.openai.desc": "The global AI standard. Maximum textual consistency and strict style respect.", - "providerTheme.minimax.badge": "Advanced", - "providerTheme.minimax.subBadge": "Performance", - "providerTheme.minimax.desc": "Incredible execution speed and excellent understanding of complex structures.", - "providerTheme.openrouter.badge": "Express", - "providerTheme.openrouter.subBadge": "Multi-model", - "providerTheme.openrouter.desc": "Unified access to the best open-source models optimized for translation.", - "providerTheme.openrouter_premium.badge": "Ultra", - "providerTheme.openrouter_premium.subBadge": "Maximum context", - "providerTheme.openrouter_premium.desc": "Assisted by state-of-the-art models (GPT-4o, Claude Sonnet 4.6) for long documents.", - "providerTheme.zai.badge": "Specialized", - "providerTheme.zai.subBadge": "Finance & Law", - "providerTheme.zai.desc": "Model fine-tuned for demanding business terminologies (legal, finance).", - "providerTheme.default.badge": "Modern", - "providerTheme.default.subBadge": "AI reasoning", - "providerTheme.default.desc": "Large language model (LLM) translation with advanced semantic analysis.", - "providerTheme.classic.google.label": "Google Translate", - "providerTheme.classic.google.desc": "Ultra-fast translation covering 130+ languages. Recommended for general flows.", - "providerTheme.classic.deepl.label": "DeepL Pro", - "providerTheme.classic.deepl.desc": "High-precision translation renowned for its fluidity and natural formulations.", - "providerTheme.classic.google_cloud.label": "Google Cloud API", - "providerTheme.classic.google_cloud.desc": "Professional cloud engine optimized for processing large volumes of documents.", - "providerSelector.noClassic": "No standard translator available.", - "providerSelector.noLlm": "No AI model configured.", - "providerSelector.costOne": "Cost: 1 credit per page", - "providerSelector.costFive": "Cost: 5 credits per page (Premium factor)", - "providerSelector.unlockContextual": "Unlock premium contextual translation for your entire documents.", - "translate.header.processing": "Processing in progress", - "translate.header.aiActive": "AI analysis active", - "translate.header.aiActiveDesc": "Your layout is being preserved by our contextual engine.", - "translate.header.completed": "Completed", - "translate.header.completedTitle": "Translation completed", - "translate.header.proSpace": "Pro space", - "translate.header.translateDoc": "Translate a document", - "translate.header.translateDocDesc": "Preserve the original layout with our ultra-high-fidelity translation engine.", - "translate.upload.nativeFormat": "Native format", - "translate.fileType.word": "Word (.docx)", - "translate.fileType.excel": "Excel (.xlsx)", - "translate.fileType.slides": "Slides (.pptx)", - "translate.fileType.pdf": "PDF (.pdf)", - "translate.startTranslation": "Start translation", - "translate.submit": "Submitting...", - "translate.chooseTargetLang": "Please choose a target language", - "translate.pleaseLoadFile": "Please upload a file first", - "translate.contextEngineActive": "Contextual engine active", - "translate.phase1": "Phase 1: Initialisation", - "translate.phase2": "Phase 2: Contextual reconstruction", - "translate.stat.segments": "segments", - "translate.stat.precision": "precision", - "translate.stat.speedLabel": "speed", - "translate.stat.turbo": "Turbo", - "translate.stat.time": "time", - "translate.complete.masterQuality": "✓ Master quality", - "translate.download": "Download", - "translate.newTranslation": "+ New translation", - "translate.failedTitle": "Translation error", - "translate.retry": "Retry", - "translate.uploadAnother": "Upload another file", - "translate.monitor": "AI monitor", - "translate.summary": "Summary", - "translate.cancelProcess": "⟳ Cancel the process", - "translate.layoutIntegrity": "Layout integrity", - "translate.secureHundred": "100% SECURE", - "translate.okHundred": "100% OK", - "translate.preserveLayout": "Preserve layout", - "translate.preserveLayoutDesc": "Preserve the layout", - "translate.textOnly": "Text only", - "translate.textOnlyDesc": "Fast translation of text only", - "translate.unavailableStandard": "Unavailable in Standard mode (AI only)", - "apiKeys.noKeysGenerated": "No keys generated", - "apiKeys.copied": "Copied!", - "services.fallback.google.label": "Google Translate", - "services.fallback.google.desc": "Fast translation, 130+ languages", - "settings.formats.excel.name": "Excel", - "settings.formats.word.name": "Word", - "settings.formats.powerpoint.name": "PowerPoint", - "pricing.dashboard": "Dashboard", - "pricing.okSymbol": "✓", - "pricing.errSymbol": "✕", - }, - - fr: { -"auth.brandName": "Wordly", - "dashboard.nav.translate": "Traduire", - "dashboard.nav.profile": "Mon Profil", - "dashboard.nav.settings": "Paramètres", - "dashboard.nav.context": "Contexte", - "dashboard.nav.services": "Services", - "dashboard.nav.apiKeys": "Clés API", - "dashboard.nav.glossaries": "Glossaires & Contexte", - "dashboard.header.title": "Dashboard", - "dashboard.header.subtitle": "Gérez vos traductions", - "dashboard.header.toggleMenu": "Menu", - "dashboard.header.profileTitle": "Mon profil", - "dashboard.sidebar.theme": "Thème", - "dashboard.sidebar.signOut": "Déconnexion", - "dashboard.sidebar.backHome": "Retour à l'accueil", - "dashboard.sidebar.upgradeToPro": "Passer Pro →", - "cookieConsent.title": "Cookies sur Wordly", - "cookieConsent.description": "Nous utilisons des cookies strictement nécessaires au fonctionnement du service (session, sécurité, langue). Avec votre accord, nous pouvons aussi utiliser des cookies optionnels pour mesurer l'audience et améliorer le produit.", - "cookieConsent.acceptAll": "Tout accepter", - "cookieConsent.essentialOnly": "Nécessaires uniquement", - "cookieConsent.learnMore": "En savoir plus", - "landing.nav.why": "Pourquoi nous ?", - "landing.nav.formats": "Formats", - "landing.nav.pricing": "Tarification", - "landing.nav.login": "Connexion", - "landing.nav.startFree": "Essai gratuit", - "landing.hero.tag": "IA Documentaire Professionnelle", - "landing.hero.titleLine1": "Traduisez vos documents.", - "landing.hero.titleLine2": "Mise en forme parfaite.", - "landing.hero.description": "Le seul traducteur qui préserve les SmartArt, graphiques, tables des matières, formes, en-têtes et pieds de page — exactement tels qu'ils étaient.", - "landing.hero.ctaMain": "Essai gratuit — 2 docs/mois", - "landing.hero.ctaSec": "Voir les offres", - "landing.hero.deleted": "Fichiers supprimés après 60 min", - "landing.hero.noHidden": "Pas de prix cachés", - "landing.hero.preview": "Aperçu avant paiement", - "landing.hero.formattedOk": "Formatage OK", - "landing.hero.aiActive": "Traduction IA active", - "landing.steps.title": "Comment ça marche ?", - "landing.steps.subtitle": "Trois étapes. Zéro perte de format.", - "landing.steps.step1.num": "01", - "landing.steps.step1.title": "Déposez votre fichier", - "landing.steps.step1.desc": "Glissez-déposez votre document Excel, Word, PowerPoint ou PDF.", - "landing.steps.step2.num": "02", - "landing.steps.step2.title": "Choisissez la langue", - "landing.steps.step2.desc": "Sélectionnez la langue cible et le moteur de traduction — classique ou IA contextuelle.", - "landing.steps.step3.num": "03", - "landing.steps.step3.title": "Téléchargez le résultat", - "landing.steps.step3.desc": "Récupérez votre document traduit avec un formatage identique à l'original.", - "landing.features.tag": "Moteur de Traduction IA", - "landing.features.title": "La traduction qui comprend votre métier", - "landing.features.description": "Nos modèles IA analysent le contexte, respectent votre terminologie et traduisent même le texte dans vos images.", - "landing.features.context.title": "Contexte métier", - "landing.features.context.desc": "Décrivez votre domaine et obtenez des traductions adaptées, pas génériques.", - "landing.features.glossary.title": "Glossaires métier", - "landing.features.glossary.desc": "Définissez vos termes techniques. CTA restera « Air Handling Unit », jamais « Call To Action ».", - "landing.features.vision.title": "Vision sur images", - "landing.features.vision.desc": "Le texte incrusté dans vos images, diagrammes et graphiques est détecté et traduit.", - "landing.features.demo.source": "Source (FR)", - "landing.features.demo.google": "Google Translate", - "landing.features.demo.ours": "Notre IA", - "landing.layout.title": "Votre mise en forme,", - "landing.layout.title2": "parfaitement préservée", - "landing.layout.subtitle": "Les autres traducteurs détruisent votre mise en page. Pas nous.", - "landing.layout.p1.title": "SmartArt et diagrammes", - "landing.layout.p1.desc": "Organigrammes, flux, hiérarchies — tout traduit à l'identique.", - "landing.layout.p2.title": "Tables des matières", - "landing.layout.p2.desc": "Entrées de TDM, numéros et renvois mis à jour correctement.", - "landing.layout.p3.title": "Graphiques", - "landing.layout.p3.desc": "Titres, étiquettes, légendes et séries — tout est traduit.", - "landing.layout.p4.title": "Formes et zones de texte", - "landing.layout.p4.desc": "Rectangles, blocs arrondis, légendes — localisé partout.", - "landing.layout.p5.title": "En-têtes et pieds de page", - "landing.layout.p5.desc": "En-têtes, pieds de page et notes ne sont jamais oubliés.", - "landing.layout.p6.title": "130+ langues", - "landing.layout.p6.desc": "Google Traduction, DeepL et moteurs IA haute performance.", - "landing.formats.title": "Chaque format,", - "landing.formats.title2": "chaque élément", - "landing.formats.subtitle": "Nous traduisons ce que les autres oublient. Votre entreprise mérite une documentation irréprochable.", - "landing.formats.word.name": "Word", - "landing.formats.word.i1": "Paragraphes et titres", - "landing.formats.word.i2": "Tableaux et graphiques", - "landing.formats.word.i3": "Diagrammes SmartArt", - "landing.formats.word.i4": "Table des matières", - "landing.formats.word.i5": "En-têtes et pieds", - "landing.formats.word.i6": "Formes et zones de texte", - "landing.formats.word.i7": "Notes de bas de page", - "landing.formats.excel.name": "Excel", - "landing.formats.excel.i1": "Valeurs de cellules", - "landing.formats.excel.i2": "Noms de feuilles", - "landing.formats.excel.i3": "Graphiques et étiquettes", - "landing.formats.excel.i4": "En-têtes et pieds", - "landing.formats.excel.i5": "Cellules fusionnées", - "landing.formats.pptx.name": "PowerPoint", - "landing.formats.pptx.i1": "Texte et notes", - "landing.formats.pptx.i2": "Graphiques et diagrammes", - "landing.formats.pptx.i3": "Formes et zones de texte", - "landing.formats.pptx.i4": "Masques de diapositives", - "landing.formats.pptx.i5": "Animations préservées", - "landing.formats.pdf.name": "PDF", - "landing.formats.pdf.i1": "PDF textuels", - "landing.formats.pdf.i2": "Mise en page préservée", - "landing.formats.pdf.i3": "Images conservées", - "landing.formats.pdf.i4": "Tableaux maintenus", - "landing.formats.pdf.i5": "Sortie DOCX ou PDF", - "landing.pricing.title": "Des prix simples et honnêtes", - "landing.pricing.subtitle": "Ce que vous voyez est ce que vous payez. Aucun frais caché.", - "landing.pricing.monthly": "Mensuel", - "landing.pricing.annual": "Annuel", - "landing.pricing.bestValue": "Le plus populaire", - "landing.pricing.month": "/mois", - "landing.pricing.footer": "Le prix affiché est le prix que vous payez. Aucun frais caché après traduction.", - "landing.pricing.starter.name": "Starter", - "landing.pricing.starter.desc": "Pour les particuliers et petits projets", - "landing.pricing.starter.f1": "50 documents / mois", - "landing.pricing.starter.f2": "Jusqu'à 50 pages par doc", - "landing.pricing.starter.f3": "Google Traduction + DeepL", - "landing.pricing.starter.f4": "Fichiers jusqu'à 10 Mo", - "landing.pricing.starter.cta": "Commencer", - "landing.pricing.pro.name": "Pro", - "landing.pricing.pro.desc": "Pour les professionnels exigeants", - "landing.pricing.pro.f1": "200 documents / mois", - "landing.pricing.pro.f2": "Jusqu'à 200 pages par doc", - "landing.pricing.pro.f3": "Traduction par IA", - "landing.pricing.pro.f4": "Google + DeepL inclus", - "landing.pricing.pro.f5": "Glossaires et prompts", - "landing.pricing.pro.f6": "Support prioritaire", - "landing.pricing.pro.cta": "Essayer Pro", - "landing.pricing.business.name": "Business", - "landing.pricing.business.desc": "Pour les équipes avec des besoins élevés", - "landing.pricing.business.f1": "1 000 documents / mois", - "landing.pricing.business.f2": "Jusqu'à 500 pages par doc", - "landing.pricing.business.f3": "IA Premium (Claude)", - "landing.pricing.business.f4": "Tous les fournisseurs + API", - "landing.pricing.business.f5": "Webhooks et automatisation", - "landing.pricing.business.f6": "5 postes d'équipe", - "landing.pricing.business.cta": "Nous contacter", - "landing.pricing.free.name": "Gratuit", - "landing.pricing.free.desc": "Idéal pour découvrir l'application", - "landing.pricing.free.cta": "Choisir ce plan", - "landing.pricing.enterprise.name": "Entreprise", - "landing.pricing.enterprise.desc": "Solutions sur mesure pour les grandes organisations", - "landing.pricing.enterprise.cta": "Nous contacter", - "landing.cta.title": "Commencez à traduire en 30 secondes", - "landing.cta.subtitle": "Aucune carte bancaire requise. Essayez gratuitement dès maintenant et redonnez vie à vos documents multilingues.", - "landing.cta.button": "Créer un compte gratuit", - "landing.cta.secure": "Sécurisé par chiffrement AES-256", - "landing.footer.desc": "Spécialiste de la traduction documentaire intelligente. Nous marions l'art de la mise en page et la science de l'IA contextuelle.", - "landing.footer.product": "Produit", - "landing.footer.resources": "Ressources", - "landing.footer.legal": "Légal", - "landing.footer.rights": "© 2026 Wordly.art — Tous droits réservés.", - "dashboard.translate.pageTitle": "Traduire un document", - "dashboard.translate.pageSubtitle": - "Importez un fichier et choisissez la langue cible", - "dashboard.translate.errorNotificationTitle": "Erreur", - "dashboard.translate.dropzone.uploadAria": "Zone de dépôt de fichier", - "dashboard.translate.dropzone.title": "Glissez-déposez votre fichier ici", - "dashboard.translate.dropzone.subtitle": - "ou cliquez pour sélectionner (DOCX, XLSX, PPTX, PDF)", - "dashboard.translate.dropzone.replaceFile": "Remplacer le fichier", - "dashboard.translate.language.source": "Langue source", - "dashboard.translate.language.target": "Langue cible", - "dashboard.translate.language.loading": "Chargement des langues…", - "dashboard.translate.language.autoDetect": "Auto-détection", - "dashboard.translate.language.selectPlaceholder": "Sélectionner…", - "dashboard.translate.language.loadErrorPrefix": - "Erreur de chargement des langues", - "dashboard.translate.provider.loading": "Chargement des fournisseurs…", - "dashboard.translate.provider.noneConfigured": - "Aucun fournisseur configuré", - "dashboard.translate.provider.modelTitle": "Modèle", - "dashboard.translate.provider.sectionTitle": "Fournisseur", - "dashboard.translate.provider.llmDivider": "IA · Context-Aware", - "dashboard.translate.provider.llmDividerPro": - "IA · Context-Aware (Pro)", - "dashboard.translate.provider.upgrade": "Passer Pro", - "dashboard.translate.provider.upgradeSuffix": - "pour débloquer la traduction IA", - "dashboard.translate.provider.tabStandard": "Standard", - "dashboard.translate.provider.tabLLM": "Multi-Modèles IA", - "translate.glossary.selectGlossary": "Sélectionner un glossaire...", - "dashboard.translate.translateImages": "Traduire les images", - "dashboard.translate.translateImagesDesc": "Extraire et traduire le texte des images (vision requise)", - "dashboard.translate.trust.zeroRetention": "Rétention zéro", - "dashboard.translate.trust.deletedAfter": - "Fichiers supprimés après traitement", - "dashboard.translate.actions.uploading": "Chargement…", - "dashboard.translate.actions.translate": "Traduire", - "dashboard.translate.actions.filePrefix": "Fichier : ", - "dashboard.translate.actions.cancel": "Annuler", - "dashboard.translate.actions.tryAgain": "Réessayer", - "dashboard.translate.steps.uploading": "Chargement du fichier…", - "dashboard.translate.steps.starting": "Démarrage de la traduction…", - "dashboard.translate.complete.title": "Traduction terminée !", - "dashboard.translate.complete.descNamed": - "Votre fichier {name} a été traduit avec succès.", - "dashboard.translate.complete.descGeneric": - "Votre fichier a été traduit avec succès.", - "dashboard.translate.complete.downloading": "Téléchargement…", - "dashboard.translate.complete.download": "Télécharger", - "dashboard.translate.complete.newTranslation": "Nouvelle traduction", - "dashboard.translate.complete.toastOkTitle": "Succès", - "dashboard.translate.complete.toastOkDesc": "{name} a été téléchargé avec succès.", - "dashboard.translate.complete.toastFailTitle": "Échec", - "dashboard.translate.complete.toastFailDesc": - "La traduction a échoué. Veuillez réessayer.", - "dashboard.translate.sourceDocument": "Document source", - "dashboard.translate.configuration": "Configuration", - "dashboard.translate.translating": "Traduction en cours", - "dashboard.translate.liveMonitor": "Moniteur en direct", - "dashboard.translate.summary": "Résumé", - "dashboard.translate.engine": "Moteur", - "dashboard.translate.confidence": "Confiance", - "dashboard.translate.cancel": "Annuler", - "dashboard.translate.segments": "Segments", - "dashboard.translate.characters": "Caractères", - "dashboard.translate.elapsed": "Écoulé", - "dashboard.translate.segPerMin": "Seg/min", - "dashboard.translate.highQuality": "Haute qualité", - "dashboard.translate.quality": "Qualité", - "dashboard.translate.completed": "Traduction terminée", - "dashboard.translate.replace": "Remplacer", - "dashboard.translate.pdfMode.title": "Mode de traduction PDF", - "dashboard.translate.pdfMode.preserveLayout": "Préserver la mise en page", - "dashboard.translate.pdfMode.textOnly": "Texte uniquement", - "dashboard.translate.pdfMode.preserveLayoutDesc": "Conserve les images, tableaux et formatage. Idéal pour les PDF simples.", - "dashboard.translate.pdfMode.textOnlyDesc": "Traduit tout le texte parfaitement. Sortie propre, sans problème de mise en page.", - "dashboard.translate.pipeline.upload": "Upload", - "dashboard.translate.pipeline.analyze": "Analyse", - "dashboard.translate.pipeline.translate": "Traduction", - "dashboard.translate.pipeline.rebuild": "Reconstruction", - "dashboard.translate.pipeline.finalize": "Finalisation", - "dashboard.translate.progress.processingFallback": "Traitement en cours…", - "dashboard.translate.progress.connectionLost": "Connexion perdue. Reconnexion…", - "dashboard.translate.progress.failedTitle": "Traduction échouée", - "dashboard.translate.error.unexpected": "Une erreur inattendue est survenue. Réessayez.", - "dashboard.translate.error.noResult": "La traduction n'a produit aucun résultat. Vérifiez que le document contient du texte, puis réessayez ou choisissez un autre moteur.", - "dashboard.translate.error.apiKey": "Clé API invalide ou manquante. Contactez l'administrateur pour configurer les clés.", - "dashboard.translate.error.quota": "Limite d'utilisation atteinte. Réessayez dans quelques minutes ou choisissez un autre moteur.", - "dashboard.translate.error.timeout": "La connexion au service de traduction a expiré. Vérifiez votre réseau et réessayez.", - "dashboard.translate.error.sessionExpired": "La session a expiré. Cliquez sur Réessayer pour relancer la traduction.", - "dashboard.translate.error.empty": "Le document semble vide ou ne contient pas de texte traduisible (PDF image ?).", - "dashboard.translate.error.unsupported": "Format de fichier non supporté ou fichier corrompu.", - "dashboard.translate.error.connection": "Connexion perdue. Vérifiez votre réseau et réessayez.", - "dashboard.translate.error.generic": "Traduction échouée : {detail}", - "dashboard.translate.error.title": "Traduction échouée", - "dashboard.translate.retry": "Réessayer la traduction", - "dashboard.translate.newFile": "Nouveau fichier", - "dashboard.translate.modeAI": "Mode IA", - "dashboard.translate.modeClassic": "Mode Classique", - "dashboard.translate.glossaryLLMHint": "Glossaires disponibles en mode IA", - "dashboard.translate.submitting": "Envoi en cours...", - "dashboard.translate.submit": "Lancer la traduction", - "dashboard.translate.noFile": "Déposez d'abord un fichier", - "dashboard.translate.noTargetLang": "Sélectionnez une langue cible", - "glossaries.yourGlossaries": "Vos glossaires", - "glossaries.title": "Glossaires & Contexte", - "glossaries.description": "Gérez vos glossaires et instructions de contexte pour des traductions plus précises.", - "glossaries.createNew": "Créer nouveau", - "glossaries.empty": "Aucun glossaire", - "glossaries.emptyDesc": "Créez votre premier glossaire ou chargez un préréglage professionnel ci-dessus", - "glossaries.defineTerms": "termes", - "glossaries.aboutTitle": "À propos des glossaires", - "glossaries.aboutDesc": "Les glossaires vous permettent de définir des traductions exactes pour des termes spécifiques. Lors de la traduction, les termes du glossaire garantissent des traductions cohérentes et précises.", - "glossaries.aboutFormat": "Chaque terme a un mot source et des traductions en plusieurs langues. Sélectionnez un glossaire dans la page de traduction pour l'appliquer.", - "glossaries.toast.created": "Glossaire créé", - "glossaries.toast.createdDesc": "Le glossaire \"{name}\" a été créé.", - "glossaries.toast.imported": "Glossaire importé", - "glossaries.toast.importedDesc": "Le glossaire \"{name}\" a été importé.", - "glossaries.toast.updated": "Glossaire mis à jour", - "glossaries.toast.updatedDesc": "Le glossaire \"{name}\" a été mis à jour.", - "glossaries.toast.deleted": "Glossaire supprimé", - "glossaries.toast.deletedDesc": "Le glossaire a été supprimé.", - "glossaries.toast.error": "Erreur", - "glossaries.toast.errorCreate": "Impossible de créer le glossaire", - "glossaries.toast.errorImport": "Impossible d'importer le glossaire", - "glossaries.toast.errorUpdate": "Impossible de mettre à jour le glossaire", - "glossaries.toast.errorDelete": "Impossible de supprimer le glossaire", - "glossaries.dialog.title": "Nouveau glossaire", - "glossaries.dialog.description": "Créez un glossaire pour vos traductions", - "glossaries.dialog.nameLabel": "Nom", - "glossaries.dialog.namePlaceholder": "Mon glossaire", - "glossaries.dialog.tabTemplates": "Modèles", - "glossaries.dialog.tabFile": "Fichier", - "glossaries.dialog.tabManual": "Manuel", - "glossaries.dialog.cancel": "Annuler", - "glossaries.dialog.creating": "Création…", - "glossaries.dialog.importing": "Import…", - "glossaries.dialog.importBtn": "Importer", - "glossaries.dialog.selectPrompt": "Sélectionner", - "glossaries.dialog.createBtn": "Créer", - "glossaries.dialog.createEmpty": "Créer vide", - "glossaries.dialog.terms": "termes", - "glossaries.dialog.templatesDesc": - "Choisissez un modèle prédéfini", - "glossaries.dialog.templatesEmpty": "Aucun modèle disponible", - "glossaries.dialog.dropTitle": "Glissez un fichier CSV ici", - "glossaries.dialog.dropOr": "ou", - "glossaries.dialog.dropFormats": "CSV, TSV, TXT", - "glossaries.termEditor.addTerm": "Ajouter un terme", - "glossaries.termEditor.maxReached": "Maximum {max} termes par glossaire atteint.", - "glossaries.dialog.formatTitle": "Format", - "glossaries.dialog.formatDesc": - "source,target (un par ligne)", - "glossaries.dialog.formatNote": - "Première ligne ignorée si en-tête détecté", - "glossaries.dialog.errorFormat": "Format non supporté", - "glossaries.dialog.errorSize": "Fichier trop volumineux", - "glossaries.dialog.errorEmpty": "Fichier vide", - "glossaries.dialog.errorRead": "Erreur de lecture", - "glossaries.dialog.parsing": "Analyse…", - "glossaries.dialog.termsImported": "termes importés", - "glossaries.dialog.changeFile": "Changer le fichier", - "glossaries.dialog.retry": "Réessayer", - "glossaries.edit.title": "Modifier le glossaire", - "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", - "glossaries.edit.nameLabel": "Nom du glossaire", - "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", - "glossaries.edit.sourceLang": "Langue source", - "glossaries.edit.targetLang": "Langue cible", - "glossaries.edit.termsLabel": "Termes ({count} valides)", - "glossaries.edit.exportCsv": "Exporter CSV", - "glossaries.edit.importCsv": "Importer CSV", - "glossaries.edit.cancel": "Annuler", - "glossaries.edit.saving": "Enregistrement...", - "glossaries.edit.saveChanges": "Enregistrer les modifications", - "glossaries.edit.importFailedTitle": "Échec de l'importation", - "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", - "glossaries.edit.importSuccessTitle": "Importation réussie", - "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", - "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", - "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", - "glossaries.delete.title": "Supprimer le glossaire", - "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", - "glossaries.delete.warning": "Cette action est irréversible", - "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", - "glossaries.delete.cancel": "Annuler", - "glossaries.delete.deleting": "Suppression...", - "glossaries.delete.deleteBtn": "Supprimer", - "glossaries.upgrade.title": "Glossaires", - "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", - "glossaries.upgrade.feature1": "Créez plusieurs glossaires", - "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", - "glossaries.upgrade.feature3": "Importez/exportez via CSV", - "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", - "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", - "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", - "glossaries.upgrade.proLabel": "Pro", - "glossaries.upgrade.upgradeBtn": "Passer à Pro", - "glossaries.loading": "Chargement...", - "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", - "glossaries.howItWorks.step1Title": "Configurez ici", - "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", - "glossaries.howItWorks.step2Title": "Activez dans Traduire", - "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", - "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", - "glossaries.howItWorks.goToTranslate": "Aller à Traduire", - "glossaries.status.unsaved": "Non enregistré", - "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", - "glossaries.status.inactive": "Inactif", - "glossaries.instructions.whatForBold": "À quoi ça sert ?", - "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", - "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", - "glossaries.instructions.charCount": "{count} caractères", - "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", - "glossaries.instructions.clearAll": "Tout effacer", - "glossaries.instructions.saving": "Enregistrement…", - "glossaries.instructions.saved": "Enregistré", - "glossaries.presets.whatForBold": "À quoi ça sert ?", - "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", - "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", - "glossaries.presets.creating": "Création…", - "glossaries.presets.alreadyImported": "Déjà importé", - "glossaries.presets.it.title": "IT / Logiciel", - "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", - "glossaries.presets.legal.title": "Juridique / Contrats", - "glossaries.presets.legal.desc": "Droit des affaires, contentieux", - "glossaries.presets.medical.title": "Médical / Santé", - "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", - "glossaries.presets.finance.title": "Finance / Comptabilité", - "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", - "glossaries.presets.marketing.title": "Marketing / Publicité", - "glossaries.presets.marketing.desc": "Digital, branding, analytics", - "glossaries.presets.hr.title": "RH / Ressources Humaines", - "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", - "glossaries.presets.scientific.title": "Scientifique / Recherche", - "glossaries.presets.scientific.desc": "Publications, thèses, articles", - "glossaries.presets.ecommerce.title": "E-commerce / Vente", - "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", - "glossaries.grid.title": "Vos", - "glossaries.grid.titleHighlight": "glossaires", - "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", - "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", - "glossaries.grid.activeTranslation": "Traduction active :", - "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", - "glossaries.badge.compatible": "Compatible", - "glossaries.badge.otherTarget": "Autre cible", - "glossaries.card.editTerms": "Modifier les termes", - "glossaries.card.created": "Créé", - "glossaries.card.term": "terme", - "glossaries.card.delete": "Supprimer", - "glossaries.grid.searchPlaceholder": "Rechercher un glossaire…", - "glossaries.grid.noResults": "Aucun résultat pour cette recherche.", - "glossaries.detail.backToList": "Retour aux glossaires", - "glossaries.detail.save": "Enregistrer", - "glossaries.detail.savedTitle": "Enregistré", - "glossaries.detail.savedDesc": "Le glossaire a été mis à jour.", - "glossaries.detail.settingsTitle": "Paramètres", - "glossaries.detail.sourceLang": "Langue source", - "glossaries.detail.targetLang": "Langue cible", - "glossaries.detail.termsTitle": "Termes", - "glossaries.detail.terms": "termes", - "glossaries.detail.searchTerms": "Filtrer…", - "glossaries.detail.noTerms": "Aucun terme pour l'instant.", - "glossaries.detail.addFirstTerm": "Ajouter le premier terme", - "glossaries.detail.addTerm": "Ajouter un terme", - "glossaries.detail.maxReached": "Limite maximale atteinte", - "glossaries.detail.source": "Source", - "glossaries.detail.target": "Cible", - "glossaries.detail.sourcePlaceholder": "terme source", - "glossaries.detail.targetPlaceholder": "terme cible", - "glossaries.detail.csvTitle": "CSV", - "glossaries.detail.csvDesc": "Exportez vos termes en CSV ou importez-en de nouveaux (remplace la liste actuelle).", - "glossaries.detail.export": "Exporter", - "glossaries.detail.import": "Importer", - "glossaries.detail.dangerTitle": "Zone danger", - "glossaries.detail.dangerDesc": "La suppression est définitive. Tous les termes associés seront perdus.", - "glossaries.detail.deleteGlossary": "Supprimer ce glossaire", - "glossaries.detail.confirmDelete": "Confirmer la suppression ?", - "glossaries.detail.confirm": "Confirmer", - "glossaries.detail.cancel": "Annuler", - "glossaries.detail.sourceLangNote": "'La source originale est en francais. Pour les autres langues, on lit le champ translations du terme (si disponible).'", - "glossaries.detail.sourceLocked": "fixé", - "glossaries.detail.sourceLockedNote": "Les templates ne stockent la source qu'en français. Le multilingue source est sur la roadmap.", - "glossaries.detail.targetLangNote": "Choisissez une langue pour voir les traductions correspondantes, ou « Multilingue » pour la valeur par défaut.", - "glossaries.detail.notFoundTitle": "Glossaire introuvable", - "glossaries.detail.notFoundDesc": "Ce glossaire n'existe pas ou vous n'y avez pas accès.", - "glossaries.detail.maxTermsTitle": "Limite atteinte", - "glossaries.detail.maxTermsDesc": "Maximum {max} termes par glossaire.", - "glossaries.detail.importEmptyTitle": "Fichier vide", - "glossaries.detail.importEmptyDesc": "Aucun terme détecté dans ce fichier.", - "glossaries.detail.importedTitle": "Importé", - "glossaries.detail.importedDesc": "{count} termes importés.", - "glossaries.detail.importErrorTitle": "Erreur de lecture", - "glossaries.detail.importErrorDesc": "Impossible de lire le fichier.", - "apiKeys.webhook.title": "Intégration Webhook", - "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", - "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", - "apiKeys.webhook.codeParam": "webhook_url", - "translate.mode.label": "Mode de traduction", - "translate.mode.classic": "Classique", - "translate.mode.classicDesc": "Rapide", - "translate.mode.proLlm": "Pro LLM", - "translate.mode.proLlmDesc": "Contextuel", - "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", - "translate.mode.upgradeLink": "Passer à Pro", - "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", - - // ── Pricing page ── - "pricing.nav.back": "Retour", - "pricing.nav.home": "Accueil", - "pricing.nav.mySubscription": "Mon abonnement", - - "pricing.header.badge": "Modèles IA mis à jour — Mars 2026", - "pricing.header.title": "Un forfait pour chaque besoin", - "pricing.header.subtitle": "Traduisez vos documents Word, Excel et PowerPoint en conservant la mise en page originale. Sans jamais saisir de clé API.", - "pricing.billing.monthly": "Mensuel", - "pricing.billing.yearly": "Annuel", - - "pricing.plans.free.name": "Gratuit", - "pricing.plans.starter.name": "Starter", - "pricing.plans.pro.name": "Pro", - "pricing.plans.business.name": "Business", - "pricing.plans.enterprise.name": "Entreprise", - - "pricing.plans.free.description": "Parfait pour découvrir l'application", - "pricing.plans.starter.description": "Pour les particuliers et petits projets", - "pricing.plans.pro.description": "Pour les professionnels et équipes en croissance", - "pricing.plans.business.description": "Pour les équipes et organisations", - "pricing.plans.enterprise.description": "Solutions sur mesure pour grandes organisations", - - "pricing.plans.pro.highlight": "Le plus populaire", - "pricing.plans.pro.badge": "POPULAIRE", - "pricing.plans.enterprise.badge": "SUR DEVIS", - - "pricing.plans.free.feat1": "5 documents / mois", - "pricing.plans.free.feat2": "Jusqu'à 15 pages par document", - "pricing.plans.free.feat3": "Google Traduction inclus", - "pricing.plans.free.feat4": "Toutes les langues (130+)", - "pricing.plans.free.feat5": "Support communautaire", - - "pricing.plans.starter.feat1": "50 documents / mois", - "pricing.plans.starter.feat2": "Jusqu'à 50 pages par document", - "pricing.plans.starter.feat3": "Google Traduction + DeepL", - "pricing.plans.starter.feat4": "Fichiers jusqu'à 10 Mo", - "pricing.plans.starter.feat5": "Support par e-mail", - "pricing.plans.starter.feat6": "Historique 30 jours", - - "pricing.plans.pro.feat1": "200 documents / mois", - "pricing.plans.pro.feat2": "Jusqu'à 200 pages par document", - "pricing.plans.pro.feat3": "Traduction IA Essentielle", - "pricing.plans.pro.feat4": "Google Traduction + DeepL", - "pricing.plans.pro.feat5": "Fichiers jusqu'à 25 Mo", - "pricing.plans.pro.feat6": "Glossaires personnalisés", - "pricing.plans.pro.feat7": "Support prioritaire", - "pricing.plans.pro.feat8": "Historique 90 jours", - - "pricing.plans.business.feat1": "1 000 documents / mois", - "pricing.plans.business.feat2": "Jusqu'à 500 pages par document", - "pricing.plans.business.feat3": "IA Essentielle + Premium (Claude Haiku)", - "pricing.plans.business.feat4": "Tous les fournisseurs de traduction", - "pricing.plans.business.feat5": "Fichiers jusqu'à 50 Mo", - "pricing.plans.business.feat6": "Accès API (10 000 appels/mois)", - "pricing.plans.business.feat7": "Webhooks de notification", - "pricing.plans.business.feat8": "Support dédié", - "pricing.plans.business.feat9": "Historique 1 an", - "pricing.plans.business.feat10": "Analytiques avancées", - - "pricing.plans.enterprise.feat1": "Documents illimités", - "pricing.plans.enterprise.feat2": "Tous les modèles IA (GPT-5, Claude Opus 4.6…)", - "pricing.plans.enterprise.feat3": "Déploiement on-premise ou cloud dédié", - "pricing.plans.enterprise.feat4": "SLA 99,9 % garanti", - "pricing.plans.enterprise.feat5": "Support 24/7 dédié", - "pricing.plans.enterprise.feat6": "Marque blanche (white-label)", - "pricing.plans.enterprise.feat7": "Équipes illimitées", - "pricing.plans.enterprise.feat8": "Intégrations sur mesure", - - "pricing.card.onRequest": "Sur devis", - "pricing.card.free": "Gratuit", - "pricing.card.perMonth": "/mois", - "pricing.card.billedYearly": "Facturé {price} € / an", - "pricing.card.documents": "Documents", - "pricing.card.pagesMax": "Pages max", - "pricing.card.aiTranslation": "Traduction IA", - "pricing.card.unlimited": "Illimité", - "pricing.card.perMonthStat": "/ mois", - "pricing.card.perDoc": "p / doc", - "pricing.card.aiEssential": "Essentielle", - "pricing.card.aiEssentialPremium": "Essentielle + Premium", - "pricing.card.aiCustom": "Sur mesure", - "pricing.card.myPlan": "Mon forfait", - "pricing.card.managePlan": "Gérer mon forfait", - "pricing.card.startFree": "Commencer gratuitement", - "pricing.card.contactUs": "Nous contacter", - "pricing.card.choosePlan": "Choisir ce forfait", - "pricing.card.processing": "Traitement…", - - "pricing.comparison.title": "Comparaison détaillée", - "pricing.comparison.subtitle": "Tout ce qui est inclus dans chaque forfait", - "pricing.comparison.feature": "Fonctionnalité", - "pricing.comparison.docsPerMonth": "Documents / mois", - "pricing.comparison.pagesMaxPerDoc": "Pages max / document", - "pricing.comparison.maxFileSize": "Taille max fichier", - "pricing.comparison.googleTranslation": "Google Traduction", - "pricing.comparison.deepl": "DeepL", - "pricing.comparison.aiEssential": "Traduction IA Essentielle", - "pricing.comparison.aiPremium": "Traduction IA Premium", - "pricing.comparison.apiAccess": "Accès API", - "pricing.comparison.priorityProcessing": "Traitement prioritaire", - "pricing.comparison.support": "Support", - "pricing.comparison.support.community": "Communauté", - "pricing.comparison.support.email": "E-mail", - "pricing.comparison.support.priority": "Prioritaire", - "pricing.comparison.support.dedicated": "Dédié", - "pricing.comparison.mb": "Mo", - - "pricing.credits.title": "Crédits supplémentaires", - "pricing.credits.subtitle": "Besoin de plus ? Achetez des crédits à l'unité, sans abonnement.", - "pricing.credits.perPage": "1 crédit = 1 page traduite.", - "pricing.credits.bestValue": "Le meilleur rapport", - "pricing.credits.unit": "crédits", - "pricing.credits.centsPerCredit": "cts / crédit", - "pricing.credits.buy": "Acheter", - - "pricing.trust.encryption.title": "Chiffrement de bout en bout", - "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 au repos", - "pricing.trust.languages.title": "130+ langues", - "pricing.trust.languages.sub": "Dont arabe, persan, hébreu (RTL)", - "pricing.trust.parallel.title": "Traitement parallèle", - "pricing.trust.parallel.sub": "IA multi-thread ultra-rapide", - "pricing.trust.availability.title": "Disponible 24/7", - "pricing.trust.availability.sub": "Uptime garanti 99,9 %", - - "pricing.aiModels.title": "Nos modèles IA — Mars 2026", - "pricing.aiModels.essential.title": "Traduction IA Essentielle", - "pricing.aiModels.essential.plan": "Forfait Pro", - "pricing.aiModels.essential.descPrefix": "Basée sur", - "pricing.aiModels.essential.descSuffix": "— le modèle IA le plus rentable de 2026. Qualité comparable aux modèles frontier à une fraction du coût.", - "pricing.aiModels.essential.modelName": "notre modèle IA Essentiel", - "pricing.aiModels.essential.context": "163K tokens de contexte", - "pricing.aiModels.essential.value": "Excellent rapport qualité/prix", - "pricing.aiModels.premium.title": "Traduction IA Premium", - "pricing.aiModels.premium.plan": "Forfait Business", - "pricing.aiModels.premium.descPrefix": "Basée sur", - "pricing.aiModels.premium.descSuffix": "d'Anthropic — précis sur les documents juridiques, médicaux et techniques complexes.", - "pricing.aiModels.premium.context": "200K tokens de contexte", - "pricing.aiModels.premium.precision": "Meilleure précision", - - "pricing.faq.title": "Questions fréquentes", - "pricing.faq.q1": "Puis-je changer de forfait à tout moment ?", - "pricing.faq.a1": "Oui. Le passage à un forfait supérieur est immédiat et proratisé. La rétrogradation prend effet à la fin de la période en cours.", - "pricing.faq.q2": "Qu'est-ce que la « Traduction IA Essentielle » ?", - "pricing.faq.a2": "C'est notre moteur IA. Il comprend le contexte de vos documents, préserve la mise en page et gère les termes techniques bien mieux qu'une traduction classique.", - "pricing.faq.q3": "Quelle est la différence entre IA Essentielle et IA Premium ?", - "pricing.faq.a3": "L'IA Essentielle utilise un modèle optimisé (excellent rapport qualité/prix). L'IA Premium utilise Claude Sonnet 4.6 d'Anthropic, plus précis sur les documents juridiques, médicaux et techniques complexes.", - "pricing.faq.q4": "Mes documents sont-ils conservés après traduction ?", - "pricing.faq.a4": "Les fichiers traduits sont disponibles selon votre forfait (30 jours Starter, 90 jours Pro, 1 an Business). Ils sont chiffrés au repos et en transit.", - "pricing.faq.q5": "Que se passe-t-il si je dépasse mon quota mensuel ?", - "pricing.faq.a5": "Vous pouvez acheter des crédits supplémentaires à l'unité, ou upgrader votre forfait. Vous êtes notifié à 80 % d'utilisation.", - "pricing.faq.q6": "Y a-t-il une version d'essai gratuite des forfaits payants ?", - "pricing.faq.a6": "Le forfait Gratuit est permanent et sans carte bancaire. Pour les forfaits Pro et Business, contactez-nous pour un accès d'essai de 14 jours.", - "pricing.faq.q7": "Quels formats de fichiers sont supportés ?", - "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx), et bientôt PDF. Tous les plans supportent les mêmes formats.", - - "pricing.cta.title": "Prêt à commencer ?", - "pricing.cta.subtitle": "Commencez gratuitement, sans carte bancaire. Passez à un forfait supérieur quand vous en avez besoin.", - "pricing.cta.createAccount": "Créer un compte gratuit", - "pricing.cta.login": "Se connecter", - - "pricing.toast.demo": "Mode démo — Stripe n'est pas encore configuré. En production, vous seriez redirigé vers le paiement pour activer le forfait {planId}.", - "pricing.toast.networkError": "Erreur réseau. Veuillez réessayer.", - "pricing.toast.paymentError": "Erreur lors de la création du paiement.", - - // ── Register page ── - "register.title": "Créer un compte", - "register.subtitle": "Commencez à traduire gratuitement", - "register.error.failed": "L'inscription a échoué", - - "register.name.label": "Nom", - "register.name.placeholder": "Votre nom", - "register.name.error": "Le nom doit contenir au moins 2 caractères", - - "register.email.label": "Adresse email", - "register.email.placeholder": "vous@exemple.com", - "register.email.error": "Adresse email invalide", - - "register.password.label": "Mot de passe", - "register.password.error": "Le mot de passe doit contenir au moins 8 caractères, une majuscule, une minuscule et un chiffre", - "register.password.show": "Afficher le mot de passe", - "register.password.hide": "Masquer le mot de passe", - "register.password.strengthLabel": "Force :", - "register.password.strength.weak": "Faible", - "register.password.strength.medium": "Moyen", - "register.password.strength.strong": "Fort", - - "register.confirmPassword.label": "Confirmer le mot de passe", - "register.confirmPassword.error": "Les mots de passe ne correspondent pas", - "register.confirmPassword.show": "Afficher", - "register.confirmPassword.hide": "Masquer", - - "register.submit.creating": "Création du compte...", - "register.submit.create": "Créer mon compte", - - "register.hasAccount": "Vous avez déjà un compte ?", - "register.login": "Se connecter", - - "register.terms.prefix": "En créant un compte, vous acceptez notre", - "register.terms.link": "utilisation du service", - - - - "login.errorTitle": "Erreur de connexion", - "login.welcomeBack": "Bienvenue", - "login.signInToContinue": "Connectez-vous pour continuer à traduire", - "login.email": "Email", - "login.emailPlaceholder": "vous@exemple.com", - "login.password": "Mot de passe", - "login.forgotPassword": "Mot de passe oublié ?", - "login.passwordPlaceholder": "••••••••", - "login.signingIn": "Connexion en cours...", - "login.signIn": "Se connecter", - "login.noAccount": "Pas encore de compte ?", - "login.signUpFree": "Créer un compte gratuit", - "login.orContinueWith": "ou continuer avec l'e-mail", - "login.google.connecting": "Connexion…", - "login.google.errorGeneric": "Une erreur est survenue avec la connexion Google.", - "login.google.errorFailed": "La connexion Google a échoué. Veuillez réessayer.", - "forgotPassword.enterEmail": "Veuillez entrer votre adresse email", - "forgotPassword.error": "Une erreur s'est produite", - "forgotPassword.title": "Mot de passe oublié", - "forgotPassword.checkEmail": "Vérifiez votre boîte mail", - "forgotPassword.subtitle": "Entrez votre email pour recevoir un lien de réinitialisation", - "forgotPassword.sentMessage": "Si un compte existe avec cette adresse, un email de réinitialisation a été envoyé.", - "forgotPassword.emailLabel": "Adresse email", - "forgotPassword.emailPlaceholder": "vous@exemple.com", - "forgotPassword.sending": "Envoi en cours...", - "forgotPassword.sendLink": "Envoyer le lien de réinitialisation", - "forgotPassword.backToLogin": "Retour à la connexion", - "forgotPassword.loading": "Chargement...", - "resetPassword.passwordRequirements": "Le mot de passe doit contenir au moins 8 caractères, une majuscule, une minuscule et un chiffre", - "resetPassword.passwordMismatch": "Les mots de passe ne correspondent pas", - "resetPassword.tokenMissing": "Token manquant. Veuillez utiliser le lien reçu par email.", - "resetPassword.error": "Une erreur s'est produite", - "resetPassword.invalidLink": "Lien invalide", - "resetPassword.invalidLinkMessage": "Ce lien de réinitialisation est invalide. Veuillez redemander un nouveau lien.", - "resetPassword.requestNewLink": "Redemander un lien", - "resetPassword.successTitle": "Mot de passe réinitialisé", - "resetPassword.newPasswordTitle": "Nouveau mot de passe", - "resetPassword.successSubtitle": "Vous allez être redirigé vers la connexion", - "resetPassword.subtitle": "Définissez votre nouveau mot de passe", - "resetPassword.successMessage": "Votre mot de passe a été réinitialisé avec succès. Vous allez être redirigé vers la page de connexion.", - "resetPassword.newPassword": "Nouveau mot de passe", - "resetPassword.showPassword": "Afficher le mot de passe", - "resetPassword.hidePassword": "Masquer le mot de passe", - "resetPassword.confirmPassword": "Confirmer le mot de passe", - "resetPassword.resetting": "Réinitialisation...", - "resetPassword.resetPassword": "Réinitialiser le mot de passe", - "resetPassword.backToLogin": "Retour à la connexion", - "resetPassword.loading": "Chargement...", - - // ── Common ── - "common.loading": "Chargement...", - - // ── Profile ── - "profile.header.title": "Mon Profil", - "profile.header.subtitle": "Gérez votre compte et vos préférences.", - "profile.tabs.account": "Compte", - "profile.tabs.subscription": "Abonnement", - "profile.tabs.preferences": "Préférences", - "profile.account.user": "Utilisateur", - "profile.account.memberSince": "Membre depuis", - "profile.plan.label": "Forfait", - "profile.plan.free": "Gratuit", - "profile.plan.starter": "Starter", - "profile.plan.pro": "Pro", - "profile.plan.business": "Business", - "profile.plan.enterprise": "Enterprise", - "profile.plan.pricePerMonth": "{price} €/mois", - "profile.subscription.canceling": "Annulation en cours", - "profile.subscription.active": "Actif", - "profile.subscription.unknown": "Inconnu", - "profile.subscription.accessUntil": "Accès jusqu'au", - "profile.subscription.renewalOn": "Renouvellement le", - "profile.subscription.upgradePlan": "Passer à un forfait payant", - "profile.subscription.changePlan": "Changer de forfait", - "profile.subscription.manageBilling": "Gérer la facturation", - "profile.subscription.billingUnavailable": "Portail de facturation non disponible.", - "profile.subscription.billingError": "Erreur lors de l'accès au portail.", - "profile.subscription.cancelSuccess": "Abonnement annulé. Vous conservez l'accès jusqu'à la fin de la période.", - "profile.subscription.cancelError": "Erreur lors de l'annulation.", - "profile.subscription.networkError": "Erreur réseau.", - "profile.usage.title": "Utilisation ce mois-ci", - "profile.usage.resetOn": "Reset le", - "profile.usage.documents": "Documents", - "profile.usage.pages": "Pages", - "profile.usage.extraCredits": "crédit supplémentaire", - "profile.usage.extraCreditsPlural": "crédits supplémentaires", - "profile.usage.quotaReached": "Quota atteint", - "profile.usage.quotaReachedDesc": "Passez à un forfait supérieur pour continuer.", - "profile.usage.unlockMore": "Débloquez plus de traductions avec un forfait payant.", - "profile.usage.viewPlans": "Voir les forfaits", - "profile.usage.includedInPlan": "Inclus dans votre forfait", - "profile.danger.title": "Zone danger", - "profile.danger.description": "L'annulation prend effet à la fin de votre période en cours. Vous conservez l'accès jusqu'à cette date.", - "profile.danger.confirm": "Êtes-vous sûr(e) ? Cette action ne peut pas être annulée.", - "profile.danger.confirmCancel": "Confirmer l'annulation", - "profile.danger.cancelSubscription": "Annuler mon abonnement", - "profile.danger.keep": "Non, garder", - "profile.prefs.interfaceLang": "Langue de l'interface", - "profile.prefs.interfaceLangDesc": "La langue est détectée automatiquement selon votre navigateur. Vous pouvez la changer manuellement.", - "profile.prefs.defaultTargetLang": "Langue cible par défaut", - "profile.prefs.selectLanguage": "Sélectionner une langue", - "profile.prefs.defaultTargetLangDesc": "Cette langue sera pré-sélectionnée lors de vos traductions.", - "profile.prefs.save": "Enregistrer", - "profile.prefs.theme": "Thème", - "profile.prefs.themeDesc": "Choisissez l'apparence de l'interface", - "profile.prefs.cache": "Cache", - "profile.prefs.cacheDesc": "Effacer le cache local peut résoudre certains problèmes d'affichage.", - "profile.prefs.clearing": "Effacement...", - "profile.prefs.clearCache": "Effacer le cache", - - // ── Settings ── - "settings.title": "Paramètres", - "settings.subtitle": "Configuration générale de l'application", - "settings.formats.title": "Formats supportés", - "settings.formats.subtitle": "Types de documents que vous pouvez traduire", - "settings.formats.formulas": "Formules", - "settings.formats.styles": "Styles", - "settings.formats.images": "Images", - "settings.formats.headers": "En-têtes", - "settings.formats.tables": "Tableaux", - "settings.formats.slides": "Slides", - "settings.formats.notes": "Notes", - "settings.cache.title": "Cache", - "settings.cache.desc": "Effacer le cache local peut résoudre certains problèmes d'affichage.", - "settings.cache.clearing": "Effacement...", - "settings.cache.clear": "Effacer le cache", - - // ── Services ── - "services.title": "Fournisseurs de traduction", - "services.subtitle": "Les fournisseurs sont configurés par l'administrateur. Vous pouvez voir ceux actuellement disponibles pour votre compte.", - "services.loading": "Chargement des fournisseurs...", - "services.noProviders": "Aucun fournisseur n'est actuellement configuré. Contactez votre administrateur.", - "services.classic": "Traduction classique", - "services.llmPro": "IA · Contextuelle (Pro)", - "services.available": "Disponible", - "services.model": "Modèle", - "services.adminOnly.title": "La configuration des fournisseurs est réservée à l'administrateur", - "services.adminOnly.desc": "Les clés API, la sélection de modèle et l'activation des fournisseurs sont gérées exclusivement par l'administrateur. Vous n'avez jamais besoin de saisir de clé API.", - - // ── API Keys ── - "apiKeys.title": "Clés API", - "apiKeys.subtitle": "Gérez vos clés API pour l'accès programmatique à l'API de traduction.", - "apiKeys.loading": "Chargement...", - "apiKeys.sectionTitle": "API & Automatisation", - "apiKeys.sectionDesc": "Générez et gérez vos clés API pour les workflows d'automatisation", - "apiKeys.keysUsed": "{total} sur {max} clés utilisées", - "apiKeys.maxReached": "Nombre maximum de clés atteint. Révoquez une clé pour en générer une nouvelle.", - "apiKeys.canGenerate": "Vous pouvez générer {count} clé supplémentaire", - "apiKeys.canGeneratePlural": "Vous pouvez générer {count} clés supplémentaires", - "apiKeys.generateNew": "Générer une nouvelle clé", - "apiKeys.keyRevoked": "Clé révoquée", - "apiKeys.keyRevokedDesc": "La clé API a été révoquée avec succès.", - "apiKeys.keyNotFound": "Clé introuvable", - "apiKeys.keyNotFoundDesc": "La clé API n'existe plus. Elle a peut-être déjà été révoquée.", - "apiKeys.error": "Erreur", - "apiKeys.revokeError": "Impossible de révoquer la clé API. Veuillez réessayer.", - "apiKeys.limitReached": "Limite atteinte", - "apiKeys.limitReachedDesc": "Vous avez atteint le maximum de 10 clés API. Révoquez une clé existante pour en générer une nouvelle.", - "apiKeys.proRequired": "Fonctionnalité Pro requise", - "apiKeys.proRequiredDesc": "Les clés API sont une fonctionnalité Pro. Veuillez mettre à niveau votre compte.", - "apiKeys.generateError": "Impossible de générer la clé API. Veuillez réessayer.", - "apiKeys.upgrade.title": "Clés API", - "apiKeys.upgrade.subtitle": "Automatisez vos traductions avec l'accès API", - "apiKeys.upgrade.feat1": "Générez des clés API illimitées", - "apiKeys.upgrade.feat2": "Automatisez la traduction de documents", - "apiKeys.upgrade.feat3": "Notifications webhook", - "apiKeys.upgrade.feat4": "Modes de traduction IA", - "apiKeys.upgrade.proFeature": "Les clés API sont une fonctionnalité {pro}. Passez à un forfait supérieur pour débloquer l'automatisation API.", - "apiKeys.upgrade.pro": "Pro", - "apiKeys.upgrade.cta": "Passer à Pro", - "apiKeys.dialog.maxTitle": "Nombre maximum de clés atteint", - "apiKeys.dialog.maxDesc": "Vous avez atteint le maximum de 10 clés API. Veuillez révoquer une clé existante avant d'en générer une nouvelle.", - "apiKeys.dialog.close": "Fermer", - "apiKeys.dialog.generated": "Clé API générée !", - "apiKeys.dialog.generatedDesc": "Votre nouvelle clé API a été créée. Copiez-la maintenant — elle ne sera plus affichée.", - "apiKeys.dialog.important": "Important :", - "apiKeys.dialog.importantDesc": "C'est la seule fois où vous verrez cette clé. Conservez-la en toute sécurité.", - "apiKeys.dialog.apiKey": "Clé API", - "apiKeys.dialog.name": "Nom :", - "apiKeys.dialog.done": "Terminé", - "apiKeys.dialog.copied": "J'ai copié la clé", - "apiKeys.dialog.generateTitle": "Générer une nouvelle clé API", - "apiKeys.dialog.generateDesc": "Créez une nouvelle clé API pour l'accès programmatique à l'API de traduction.", - "apiKeys.dialog.keyName": "Nom de la clé (facultatif)", - "apiKeys.dialog.keyNamePlaceholder": "ex : Production, Staging", - "apiKeys.dialog.keyNameHint": "Un nom descriptif pour vous aider à identifier cette clé plus tard.", - "apiKeys.dialog.nameTooLong": "Le nom ne doit pas dépasser {max} caractères", - "apiKeys.dialog.nameInvalid": "Le nom ne peut contenir que des lettres, chiffres, espaces, tirets et tirets bas", - "apiKeys.dialog.cancel": "Annuler", - "apiKeys.dialog.generating": "Génération...", - "apiKeys.dialog.generate": "Générer la clé", - "apiKeys.table.name": "Nom", - "apiKeys.table.prefix": "Préfixe", - "apiKeys.table.created": "Créée", - "apiKeys.table.lastUsed": "Dernière utilisation", - "apiKeys.table.never": "Jamais", - "apiKeys.table.actions": "Actions", - "apiKeys.table.revoke": "Révoquer", - "apiKeys.table.copyPrefix": "Copier le préfixe de la clé", - "apiKeys.table.revokeKey": "Révoquer la clé", - "apiKeys.revokeDialog.title": "Révoquer la clé API", - "apiKeys.revokeDialog.desc": "Êtes-vous sûr de vouloir révoquer la clé « {name} » ? Cette action est irréversible.", - "apiKeys.revokeDialog.confirm": "Oui, révoquer", - "apiKeys.revokeDialog.cancel": "Annuler", - - // ── Context & Glossary ── - "context.proTitle": "Fonctionnalité Pro", - "context.proDesc": "Le contexte et les glossaires professionnels sont disponibles avec les forfaits Pro, Business et Enterprise. Ils permettent d'obtenir des traductions plus précises grâce à des instructions et un vocabulaire spécifiques à votre domaine.", - "context.viewPlans": "Voir les forfaits", - "context.title": "Contexte & Glossaire", - "context.subtitle": "Améliorez la qualité de traduction avec des instructions et un vocabulaire spécifiques à votre domaine.", - "context.presets.title": "Glossaires professionnels", - "context.presets.desc": "Chargez un glossaire complet avec instructions et terminologie spécialisée", - "context.instructions.title": "Instructions de contexte", - "context.instructions.desc": "Instructions que l'IA suivra pendant la traduction", - "context.instructions.placeholder": "Ex : Vous traduisez des documents techniques HVAC. Utilisez une terminologie d'ingénierie précise...", - "context.glossary.title": "Glossaire technique", - "context.glossary.desc": "Format : source=cible (un par ligne). Les glossaires chargés via preset sont modifiables.", - "context.glossary.terms": "termes dans le glossaire", - "context.clearAll": "Tout effacer", - "context.saving": "Enregistrement...", - "context.save": "Enregistrer", - "translate.glossary.title": "Glossaire", - "translate.glossary.select": "Sélectionner un glossaire", - "translate.glossary.none": "Aucun", - "translate.glossary.terms": "termes", - "translate.glossary.proOnly": "Passez à Pro pour utiliser les glossaires", - "translate.glossary.myGlossaries": "Mes glossaires", - "translate.glossary.fromTemplate": "Créer depuis un template", - "translate.glossary.noGlossaryForPair": "Aucun glossaire pour", - "translate.glossary.noGlossaries": "Aucun glossaire", - "translate.glossary.loading": "Chargement...", - "translate.glossary.classicMode": "Moteur neutre sans glossaire (IA uniquement)", - "translate.glossary.selectPlaceholder": "Sélectionner un glossaire...", - "translate.glossary.multilingual": "MULTILINGUE", - "translate.glossary.noGlossaryAvailable": "Aucun glossaire disponible", - "translate.glossary.filterByLang": "Filtrer par langue", - "translate.glossary.active": "Actif", - "translate.glossary.inactive": "Inactif", - "translate.glossary.availableTemplates": "Modèles disponibles", - "translate.glossary.importing": "Importation...", - "translate.glossary.imported": "(Importé)", - "translate.glossary.noGlossaryForSource": "Aucun glossaire ni modèle pour la langue source", - "translate.glossary.createGlossary": "Créer un glossaire", - "translate.glossary.showAll": "Afficher tous les glossaires", - "translate.glossary.activePreview": "Aperçu des correspondances actives :", - "translate.glossary.total": "au total", - "translate.glossary.moreTerms": "autres termes", - "translate.glossary.noTerms": "Aucun terme dans ce glossaire.", - "translate.glossary.sourceTerm": "Terme Source", - "translate.glossary.translation": "Traduction", - "translate.glossary.addTerm": "Ajouter le terme", - "translate.glossary.disabledMode": "Moteur neutre sans glossaire appliqué", - "translate.glossary.addTermError": "Erreur lors de l'ajout du terme", - "translate.glossary.networkError": "Erreur réseau", - "translate.glossary.importFailed": "Échec de l'importation ({status})", - "translate.glossary.helpText": "Le glossaire force la traduction de termes précis. Choisissez un glossaire dont la langue source correspond à la langue d'origine de votre document.", - "translate.glossary.sourceWarning": "Attention : Ce glossaire utilise la langue source", - "translate.glossary.sourceWarningBut": "mais votre document est configuré en", - "translate.glossary.targetWarning": "Incompatibilité de cible : Ce glossaire est prévu pour traduire vers", - "translate.glossary.targetWarningBut": "mais votre document cible", - "translate.glossary.targetWarningEnd": "Les termes risquent de ne pas être pertinents.", - "context.presets.createGlossary": "Créer le glossaire", - "context.presets.created": "Glossaire créé", - "context.presets.createdDesc": "Le glossaire \"{name}\" a été créé avec {count} termes.", - "context.presets.hint": "Cliquez sur un preset pour créer un glossaire avec des termes spécifiques au domaine. Gérez vos glossaires dans la section Glossaires.", - "context.glossary.manage": "Gérer les glossaires", - "context.saved": "Enregistré", - "context.savedDesc": "Vos instructions de contexte ont été enregistrées.", - - // ── Admin ── - "admin.login.title": "Administration", - "admin.login.required": "Connexion requise", - "admin.login.password": "Mot de passe administrateur", - "admin.login.connecting": "Connexion...", - "admin.login.access": "Accéder au panneau admin", - "admin.login.restricted": "Accès réservé aux administrateurs", - "admin.layout.checking": "Vérification de l'authentification...", - "admin.dashboard.title": "Dashboard Admin", - "admin.dashboard.subtitle": "Panneau de contrôle administrateur", - "admin.dashboard.refresh": "Actualiser", - "admin.dashboard.refreshTooltip": "Actualiser les données du dashboard", - "admin.dashboard.config": "Configuration système", - "admin.dashboard.maxFileSize": "Taille max fichier :", - "admin.dashboard.translationService": "Service de traduction :", - "admin.dashboard.formats": "Formats :", - "admin.nav.dashboard": "Dashboard", - "admin.nav.users": "Utilisateurs", - "admin.nav.pricing": "Tarifs & Stripe", - "admin.nav.providers": "Fournisseurs", - "admin.nav.system": "Système", - "admin.nav.logs": "Logs", - "admin.users.title": "Gestion des Utilisateurs", - "admin.users.subtitle": "Visualiser et gérer les comptes utilisateurs", - "admin.users.planUpdated": "Plan mis à jour", - "admin.users.planChanged": "Le plan a été changé vers \"{plan}\" avec succès.", - "admin.users.unknownError": "Erreur inconnue", - "admin.users.error": "Erreur", - "admin.users.planUpdateError": "Impossible de mettre à jour le plan : {message}", - "admin.users.noKeys": "Aucune clé", - "admin.users.noKeysDesc": "Cet utilisateur n'a pas de clés API actives.", - "admin.users.keysRevoked": "Clés révoquées", - "admin.users.keysRevokedDesc": "{count} clé(s) API révoquée(s) avec succès.", - "admin.users.revokeError": "Impossible de révoquer les clés : {message}", - "admin.users.retry": "Réessayer", - "admin.system.title": "Système", - "admin.system.subtitle": "Surveiller l'état du système et gérer les ressources", - "admin.system.quotas": "Quotas de traduction", - "admin.system.resetQuotas": "Réinitialiser les quotas mensuels", - "admin.system.resetting": "Réinitialisation...", - "admin.system.reset": "Réinitialiser", - "admin.system.allOperational": "Tous les systèmes opérationnels", - "admin.system.issuesDetected": "Problèmes système détectés", - "admin.system.waitingData": "En attente de données...", - "admin.system.purging": "Purge...", - "admin.system.clean": "Nettoyer", - "admin.system.purge": "Purger", - "memento.title": "Découvrez Momento", - "memento.slogan": "Momento n'est pas qu'une simple application de notes. C'est un écosystème intelligent qui connecte, analyse et développe vos idées en temps réel grâce à 6 types d'agents IA et une recherche sémantique de pointe.", - "memento.ctaFree": "Commencer gratuitement", - "memento.ctaMore": "Voir plus", - "common.backToHome": "Retour à l'accueil", - "dashboard.topbar.interfaceLabel": "Interface de traduction", - "dashboard.topbar.premiumAccess": "Accès Premium", - "landing.hero.contextEngine": "Traduction détectée : Terme technique de maintenance pour systèmes CVC...", - "landing.hero.liveAnalysis": "Analyse en direct", - "landing.hero.termsDetected": "termes détectés", - "landing.steps.process": "PROCESSUS", - "landing.translate.newProject": "Nouveau projet", - "landing.translate.title": "Traduire un document", - "landing.translate.subtitle": "Importez un fichier et choisissez la langue cible", - "landing.translate.sourceDocument": "Document source", - "landing.translate.configuration": "Configuration", - "landing.translate.sourceLang": "Langue source", - "landing.translate.targetLang": "Langue cible", - "landing.translate.provider": "Fournisseur", - "landing.translate.startTranslation": "Lancer la traduction", - "landing.translate.zeroRetention": "Rétention zéro", - "landing.translate.filesDeleted": "Fichiers supprimés après traitement", - "landing.translate.dropHere": "Glissez-déposez ici", - "landing.translate.supportedFormats": "Fichiers DOCX, XLSX, PPTX ou PDF supportés", - "landing.translate.aiAnalysis": "Analyse IA Active", - "landing.translate.processing": "Traitement en cours", - "landing.translate.preservingLayout": "Votre mise en page est en cours de préservation", - "layout.nav.apiAccess": "Accès API", - "layout.footer.terms": "CGU", - "layout.footer.privacy": "Confidentialité", - "fileUploader.uploadDocument": "Téléverser un document", - "fileUploader.uploadDesc": "Glissez-déposez ou cliquez pour sélectionner un fichier (Excel, Word, PowerPoint)", - "fileUploader.dropHere": "Déposez votre fichier ici…", - "fileUploader.dragAndDrop": "Glissez-déposez votre document ici", - "fileUploader.orClickBrowse": "ou cliquez pour parcourir", - "fileUploader.preview": "Aperçu", - "fileUploader.translationOptions": "Options de traduction", - "fileUploader.configureSettings": "Configurez vos paramètres de traduction", - "fileUploader.targetLanguage": "Langue cible", - "fileUploader.selectLanguage": "Sélectionner une langue", - "fileUploader.translationProvider": "Fournisseur de traduction", - "fileUploader.selectProvider": "Sélectionner un fournisseur", - "fileUploader.advancedOptions": "Options avancées", - "fileUploader.translateImages": "Traduire les images", - "fileUploader.translating": "Traduction…", - "fileUploader.translateDocument": "Traduire le document", - "fileUploader.processing": "Traitement…", - "fileUploader.translationError": "Erreur de traduction", - "fileUploader.translationComplete": "Traduction terminée !", - "fileUploader.translationCompleteDesc": "Votre document a été traduit avec succès tout en préservant la mise en forme.", - "fileUploader.download": "Télécharger le document traduit", - "fileUploader.webgpuUnsupported": "WebGPU n'est pas pris en charge dans ce navigateur. Veuillez utiliser Chrome 113+ ou Edge 113+.", - "fileUploader.webllmNotLoaded": "Modèle WebLLM non chargé. Allez dans Paramètres > Services de traduction pour charger un modèle.", - "fileUploader.extracting": "Extraction des textes du document…", - "fileUploader.noTranslatable": "Aucun texte traduisible trouvé dans le document", - "fileUploader.foundTexts": "{count} textes trouvés à traduire", - "fileUploader.translatingItem": "Traduction {current}/{total} : « {preview} »", - "fileUploader.reconstructing": "Reconstruction du document…", - "fileUploader.translatingLocally": "Traduction locale avec WebLLM…", - "checkout.activating": "Activation en cours…", - "checkout.activatingDesc": "Nous mettons à jour votre abonnement, veuillez patienter.", - "checkout.paymentConfirmed": "Paiement confirmé !", - "checkout.subscriptionActivated": "Abonnement activé !", - "checkout.planActivated": "Forfait {plan} activé !", - "checkout.redirectingToProfile": "Redirection vers votre profil…", - "checkout.paymentReceived": "Paiement reçu", - "checkout.redirecting": "Redirection…", - "checkout.syncError": "Erreur de synchronisation", - "checkout.networkError": "Erreur réseau. Votre paiement est confirmé — rechargez votre profil.", - "dashboard.checkoutSyncError": "Erreur lors de la synchronisation du paiement.", - "dashboard.networkRefresh": "Erreur réseau. Veuillez rafraîchir la page.", - "dashboard.continueToTranslate": "Continuer vers la traduction", - "langSelector.search": "Rechercher…", - "langSelector.noResults": "Aucun résultat", - "langSelector.source": "Source", - "langSelector.target": "Cible", - "langSelector.swap": "Inverser", - "translateComplete.highQuality": "Haute qualité", - "translateComplete.segments": "Segments", - "translateComplete.characters": "Caractères", - "translateComplete.confidence": "Confiance", - "providerTheme.deepseek.badge": "Essentielle", - "providerTheme.deepseek.subBadge": "Technique & Éco", - "providerTheme.deepseek.desc": "Traduction ultra-précise et économique, idéale pour les documents techniques et le code.", - "providerTheme.openai.badge": "Premium", - "providerTheme.openai.subBadge": "Haute Fidélité", - "providerTheme.openai.desc": "Le standard mondial de l'IA. Cohérence textuelle maximale et respect strict du style.", - "providerTheme.minimax.badge": "Avancée", - "providerTheme.minimax.subBadge": "Performance", - "providerTheme.minimax.desc": "Vitesse d'exécution incroyable et excellente compréhension des structures complexes.", - "providerTheme.openrouter.badge": "Express", - "providerTheme.openrouter.subBadge": "Multi-Modèles", - "providerTheme.openrouter.desc": "Accès unifié aux meilleurs modèles open-source optimisés pour la traduction.", - "providerTheme.openrouter_premium.badge": "Ultra", - "providerTheme.openrouter_premium.subBadge": "Maximum Context", - "providerTheme.openrouter_premium.desc": "Traduction assistée par les modèles de pointe (GPT-4o, Claude Sonnet 4.6) pour documents longs.", - "providerTheme.zai.badge": "Spécialisée", - "providerTheme.zai.subBadge": "Finance & Droit", - "providerTheme.zai.desc": "Modèle affiné pour les terminologies métiers exigeantes (juridique, finance).", - "providerTheme.default.badge": "Moderne", - "providerTheme.default.subBadge": "Raisonnement IA", - "providerTheme.default.desc": "Traduction par grand modèle linguistique (LLM) avec analyse sémantique avancée.", - "providerTheme.classic.google.label": "Google Traduction", - "providerTheme.classic.google.desc": "Traduction ultra-rapide couvrant plus de 130 langues. Recommandé pour les flux généraux.", - "providerTheme.classic.deepl.label": "DeepL Pro", - "providerTheme.classic.deepl.desc": "Traduction haute précision réputée pour sa fluidité et ses formulations naturelles.", - "providerTheme.classic.google_cloud.label": "Google Cloud API", - "providerTheme.classic.google_cloud.desc": "Moteur cloud professionnel optimisé pour le traitement de gros volumes de documents.", - "providerSelector.noClassic": "Aucun traducteur standard disponible.", - "providerSelector.noLlm": "Aucun modèle IA configuré.", - "providerSelector.costOne": "Coût : 1 crédit par page", - "providerSelector.costFive": "Coût : 5 crédits par page (Facteur Premium)", - "providerSelector.unlockContextual": "Débloquez la traduction contextuelle haut de gamme pour vos documents entiers.", - "translate.header.processing": "Traitement en cours", - "translate.header.aiActive": "Analyse IA active", - "translate.header.aiActiveDesc": "Votre mise en page est en cours de préservation par notre moteur contextuel.", - "translate.header.completed": "Complété", - "translate.header.completedTitle": "Traduction terminée", - "translate.header.proSpace": "Espace Pro", - "translate.header.translateDoc": "Traduire un document", - "translate.header.translateDocDesc": "Conservez la mise en page d'origine grâce au moteur de traduction ultra-haute fidélité.", - "translate.upload.nativeFormat": "Format natif", - "translate.fileType.word": "Word (.docx)", - "translate.fileType.excel": "Excel (.xlsx)", - "translate.fileType.slides": "Slides (.pptx)", - "translate.fileType.pdf": "PDF (.pdf)", - "translate.startTranslation": "Lancer la traduction", - "translate.submit": "Soumission…", - "translate.chooseTargetLang": "Veuillez choisir une langue cible", - "translate.pleaseLoadFile": "Veuillez charger un fichier d'abord", - "translate.contextEngineActive": "Moteur contextuel actif", - "translate.phase1": "Phase 1 : Initialisation", - "translate.phase2": "Phase 2 : Reconstruction contextuelle", - "translate.stat.segments": "segments", - "translate.stat.precision": "précision", - "translate.stat.speedLabel": "vitesse", - "translate.stat.turbo": "Turbo", - "translate.stat.time": "temps", - "translate.complete.masterQuality": "✓ Qualité Maître", - "translate.download": "Télécharger", - "translate.newTranslation": "+ Nouvelle traduction", - "translate.failedTitle": "Erreur lors de la traduction", - "translate.retry": "Réessayer", - "translate.uploadAnother": "Téléverser un autre fichier", - "translate.monitor": "Moniteur IA", - "translate.summary": "Récapitulatif", - "translate.cancelProcess": "⟳ Annuler le processus", - "translate.layoutIntegrity": "Intégrité Layout", - "translate.secureHundred": "100% SÉCURISÉ", - "translate.okHundred": "100% OK", - "translate.preserveLayout": "Conserver la mise en page", - "translate.preserveLayoutDesc": "Conserver la mise en page", - "translate.textOnly": "Texte brut", - "translate.textOnlyDesc": "Traduction rapide du texte uniquement", - "translate.unavailableStandard": "Indisponible en mode Standard (IA uniquement)", - "apiKeys.noKeysGenerated": "Aucune clé générée", - "apiKeys.copied": "Copié !", - "services.fallback.google.label": "Google Traduction", - "services.fallback.google.desc": "Traduction rapide, 130+ langues", - "settings.formats.excel.name": "Excel", - "settings.formats.word.name": "Word", - "settings.formats.powerpoint.name": "PowerPoint", - "pricing.dashboard": "Tableau de bord", - "pricing.okSymbol": "✓", - "pricing.errSymbol": "✕", - }, - // ═══════════════════════════════════════════════════════════════ - // SPANISH (es) - // ═══════════════════════════════════════════════════════════════ - es: { - "auth.brandName": "Wordly", - "dashboard.nav.translate": "Traducir", - "dashboard.nav.profile": "Mi perfil", - "dashboard.nav.settings": "Configuración", - "dashboard.nav.context": "Contexto", - "dashboard.nav.services": "Servicios", - "dashboard.nav.apiKeys": "Claves API", - "dashboard.nav.glossaries": "Glosarios", - "dashboard.header.title": "Panel de control", - "dashboard.header.subtitle": "Gestiona tus traducciones", - "dashboard.header.toggleMenu": "Menú", - "dashboard.header.profileTitle": "Mi perfil", - "dashboard.sidebar.theme": "Tema", - "dashboard.sidebar.signOut": "Cerrar sesión", - "dashboard.sidebar.backHome": "Volver al inicio", - "dashboard.sidebar.upgradeToPro": "Pasar a Pro →", - "cookieConsent.title": "Cookies en Wordly", - "cookieConsent.description": "Usamos cookies esenciales para que la aplicación funcione (sesión, seguridad, idioma). Con su permiso, también usamos cookies opcionales para medir el tráfico y mejorar el producto.", - "cookieConsent.acceptAll": "Aceptar todas", - "cookieConsent.essentialOnly": "Solo esenciales", - "cookieConsent.learnMore": "Más información", - "landing.nav.why": "¿Por qué nosotros?", - "landing.nav.formats": "Formatos", - "landing.nav.pricing": "Precios", - "landing.nav.login": "Iniciar sesión", - "landing.nav.startFree": "Prueba gratis", - "landing.hero.tag": "IA Documental Profesional", - "landing.hero.titleLine1": "Traduce tus documentos.", - "landing.hero.titleLine2": "Con formato perfecto.", - "landing.hero.description": "El único traductor que preserva SmartArt, gráficos, índices, formas y diseños complejos — exactamente como eran.", - "landing.hero.ctaMain": "Prueba gratis — 2 docs/mes", - "landing.hero.ctaSec": "Ver ofertas", - "landing.hero.deleted": "Archivos eliminados tras 60 min", - "landing.hero.noHidden": "Sin cargos ocultos", - "landing.hero.preview": "Vista previa antes de pagar", - "landing.hero.formattedOk": "Formato OK", - "landing.hero.aiActive": "Traducción IA activa", - "landing.steps.title": "¿Cómo funciona?", - "landing.steps.subtitle": "Tres pasos. Cero pérdida de formato.", - "landing.steps.step1.num": "01", - "landing.steps.step1.title": "Sube tu archivo", - "landing.steps.step1.desc": "Arrastra y suelta tu documento Excel, Word, PowerPoint o PDF.", - "landing.steps.step2.num": "02", - "landing.steps.step2.title": "Elige idioma y motor", - "landing.steps.step2.desc": "Selecciona el idioma destino y el motor — clásico o IA contextual.", - "landing.steps.step3.num": "03", - "landing.steps.step3.title": "Descarga el resultado", - "landing.steps.step3.desc": "Obtén tu documento traducido con un formato idéntico al original.", - "landing.features.tag": "Motor de Traducción IA", - "landing.features.title": "Una traducción que entiende tu oficio", - "landing.features.description": "Nuestros modelos de IA analizan el contexto, respetan tu terminología y hasta traducen el texto dentro de las imágenes.", - "landing.features.context.title": "Contexto sectorial", - "landing.features.context.desc": "Describe tu sector y obtén traducciones adaptadas, no genéricas.", - "landing.features.glossary.title": "Glosarios sectoriales", - "landing.features.glossary.desc": "Define tus términos técnicos. CTA será «Unidad de Tratamiento de Aire», nunca «Llamada a la Acción».", - "landing.features.vision.title": "Visión de imágenes", - "landing.features.vision.desc": "El texto incrustado en imágenes, diagramas y gráficos se detecta y traduce.", - "landing.features.demo.source": "Origen (FR)", - "landing.features.demo.google": "Google Translate", - "landing.features.demo.ours": "Nuestra IA", - "landing.layout.title": "Tu formato,", - "landing.layout.title2": "perfectamente conservado", - "landing.layout.subtitle": "Otros traductores rompen tu diseño. Nosotros no.", - "landing.layout.p1.title": "SmartArt y diagramas", - "landing.layout.p1.desc": "Organigramas, flujos, jerarquías — todo traducido idénticamente.", - "landing.layout.p2.title": "Índices de contenido", - "landing.layout.p2.desc": "Entradas del índice, números de página y referencias cruzadas actualizados correctamente.", - "landing.layout.p3.title": "Gráficos y diagramas", - "landing.layout.p3.desc": "Títulos, etiquetas de ejes, leyendas y nombres de series — todo traducido.", - "landing.layout.p4.title": "Formas y cuadros de texto", - "landing.layout.p4.desc": "Rectángulos, bloques redondeados, llamadas — localizados en todas partes.", - "landing.layout.p5.title": "Encabezados y pies de página", - "landing.layout.p5.desc": "Encabezados, pies de página y notas al pie nunca se pasan por alto.", - "landing.layout.p6.title": "130+ idiomas", - "landing.layout.p6.desc": "Google Translate, DeepL y motores de IA de grado profesional.", - "landing.formats.title": "Cada formato,", - "landing.formats.title2": "cada elemento", - "landing.formats.subtitle": "Traducimos lo que otros olvidan. Tu empresa merece una documentación impecable.", - "landing.formats.word.name": "Word", - "landing.formats.word.i1": "Párrafos y encabezados", - "landing.formats.word.i2": "Tablas y gráficos", - "landing.formats.word.i3": "Diagramas SmartArt", - "landing.formats.word.i4": "Índice de contenido", - "landing.formats.word.i5": "Encabezados y pies", - "landing.formats.word.i6": "Formas y cuadros de texto", - "landing.formats.word.i7": "Notas al pie y al final", - "landing.formats.excel.name": "Excel", - "landing.formats.excel.i1": "Valores de celdas", - "landing.formats.excel.i2": "Nombres de hojas", - "landing.formats.excel.i3": "Gráficos y etiquetas", - "landing.formats.excel.i4": "Encabezados y pies", - "landing.formats.excel.i5": "Celdas combinadas conservadas", - "landing.formats.pptx.name": "PowerPoint", - "landing.formats.pptx.i1": "Texto de diapositivas y notas", - "landing.formats.pptx.i2": "Gráficos y diagramas", - "landing.formats.pptx.i3": "Formas y cuadros de texto", - "landing.formats.pptx.i4": "Diseños maestros", - "landing.formats.pptx.i5": "Animaciones conservadas", - "landing.formats.pdf.name": "PDF", - "landing.formats.pdf.i1": "PDF basados en texto", - "landing.formats.pdf.i2": "Diseño conservado", - "landing.formats.pdf.i3": "Imágenes en su lugar", - "landing.formats.pdf.i4": "Tablas mantenidas", - "landing.formats.pdf.i5": "Salida como DOCX o PDF", - "landing.pricing.title": "Precios simples y honestos", - "landing.pricing.subtitle": "Lo que ves es lo que pagas. Sin cargos ocultos.", - "landing.pricing.monthly": "Mensual", - "landing.pricing.annual": "Anual", - "landing.pricing.bestValue": "Más popular", - "landing.pricing.month": "/mes", - "landing.pricing.footer": "El precio mostrado es el precio que pagas. Sin cargos ocultos después de la traducción.", - "landing.pricing.starter.name": "Starter", - "landing.pricing.starter.desc": "Para particulares y proyectos pequeños", - "landing.pricing.starter.f1": "50 documentos / mes", - "landing.pricing.starter.f2": "Hasta 50 páginas por doc", - "landing.pricing.starter.f3": "Google Translate + DeepL", - "landing.pricing.starter.f4": "Archivos de hasta 10 MB", - "landing.pricing.starter.cta": "Empezar", - "landing.pricing.pro.name": "Pro", - "landing.pricing.pro.desc": "Para profesionales exigentes", - "landing.pricing.pro.f1": "200 documentos / mes", - "landing.pricing.pro.f2": "Hasta 200 páginas por doc", - "landing.pricing.pro.f3": "Traducción con IA", - "landing.pricing.pro.f4": "Google + DeepL incluidos", - "landing.pricing.pro.f5": "Glosarios y prompts personalizados", - "landing.pricing.pro.f6": "Soporte prioritario", - "landing.pricing.pro.cta": "Probar Pro", - "landing.pricing.business.name": "Business", - "landing.pricing.business.desc": "Para equipos con grandes necesidades", - "landing.pricing.business.f1": "1 000 documentos / mes", - "landing.pricing.business.f2": "Hasta 500 páginas por doc", - "landing.pricing.business.f3": "IA Premium (Claude)", - "landing.pricing.business.f4": "Todos los proveedores + API", - "landing.pricing.business.f5": "Webhooks y automatización", - "landing.pricing.business.f6": "5 puestos de equipo", - "landing.pricing.business.cta": "Contáctenos", - "landing.cta.title": "Empieza a traducir en 30 segundos", - "landing.cta.subtitle": "No se necesita tarjeta de crédito. Prueba gratis ahora y da vida a tus documentos multilingües.", - "landing.cta.button": "Crear cuenta gratuita", - "landing.cta.secure": "Protegido con cifrado AES-256", - "landing.footer.desc": "Especialistas en traducción inteligente de documentos. Combinamos el arte del diseño con la ciencia de la IA contextual.", - "landing.footer.product": "Producto", - "landing.footer.resources": "Recursos", - "landing.footer.legal": "Legal", - "landing.footer.rights": "© 2026 Wordly.art — Todos los derechos reservados.", - "dashboard.translate.pageTitle": "Traducir un documento", - "dashboard.translate.pageSubtitle": "Importa un archivo y elige el idioma de destino", - "dashboard.translate.errorNotificationTitle": "Error", - "dashboard.translate.dropzone.uploadAria": "Zona para soltar archivos", - "dashboard.translate.dropzone.title": "Arrastra y suelta tu archivo aquí", - "dashboard.translate.dropzone.subtitle": "o haz clic para seleccionar (DOCX, XLSX, PPTX, PDF)", - "dashboard.translate.dropzone.replaceFile": "Reemplazar archivo", - "dashboard.translate.language.source": "Idioma de origen", - "dashboard.translate.language.target": "Idioma de destino", - "dashboard.translate.language.loading": "Cargando idiomas…", - "dashboard.translate.language.autoDetect": "Detección automática", - "dashboard.translate.language.selectPlaceholder": "Seleccionar…", - "dashboard.translate.language.loadErrorPrefix": "Error al cargar los idiomas", - "dashboard.translate.provider.loading": "Cargando proveedores…", - "dashboard.translate.provider.noneConfigured": "No hay proveedores configurados", - "dashboard.translate.provider.modelTitle": "Modelo", - "dashboard.translate.provider.sectionTitle": "Proveedor", - "dashboard.translate.provider.llmDivider": "IA · Contextual", - "dashboard.translate.provider.llmDividerPro": "IA · Contextual (Pro)", - "dashboard.translate.provider.upgrade": "Mejorar a Pro", - "dashboard.translate.provider.upgradeSuffix": "para desbloquear la traducción IA", - "dashboard.translate.trust.zeroRetention": "Sin retención", - "dashboard.translate.trust.deletedAfter": "Archivos eliminados tras el procesamiento", - "dashboard.translate.actions.uploading": "Subiendo…", - "dashboard.translate.actions.translate": "Traducir", - "dashboard.translate.actions.filePrefix": "Archivo: ", - "dashboard.translate.actions.cancel": "Cancelar", - "dashboard.translate.actions.tryAgain": "Reintentar", - "dashboard.translate.steps.uploading": "Subiendo archivo…", - "dashboard.translate.steps.starting": "Iniciando traducción…", - "dashboard.translate.complete.title": "¡Traducción completada!", - "dashboard.translate.complete.descNamed": "Tu archivo {name} se ha traducido correctamente.", - "dashboard.translate.complete.descGeneric": "Tu archivo se ha traducido correctamente.", - "dashboard.translate.complete.downloading": "Descargando…", - "dashboard.translate.complete.download": "Descargar", - "dashboard.translate.complete.newTranslation": "Nueva traducción", - "dashboard.translate.complete.toastOkTitle": "Éxito", - "dashboard.translate.complete.toastOkDesc": "{name} se ha descargado correctamente.", - "dashboard.translate.complete.toastFailTitle": "Error", - "dashboard.translate.complete.toastFailDesc": "La traducción ha fallado. Por favor, inténtalo de nuevo.", - "dashboard.translate.sourceDocument": "Documento fuente", - "dashboard.translate.configuration": "Configuración", - "dashboard.translate.translating": "Traducción en progreso", - "dashboard.translate.liveMonitor": "Monitor en vivo", - "dashboard.translate.summary": "Resumen", - "dashboard.translate.engine": "Motor", - "dashboard.translate.confidence": "Confianza", - "dashboard.translate.cancel": "Cancelar", - "dashboard.translate.segments": "Segmentos", - "dashboard.translate.characters": "Caracteres", - "dashboard.translate.elapsed": "Transcurrido", - "dashboard.translate.segPerMin": "Seg/min", - "dashboard.translate.highQuality": "Alta calidad", - "dashboard.translate.quality": "Calidad", - "dashboard.translate.completed": "Traducción completada", - "dashboard.translate.replace": "Reemplazar", - "dashboard.translate.pdfMode.title": "Modo de traducción PDF", - "dashboard.translate.pdfMode.preserveLayout": "Conservar diseño", - "dashboard.translate.pdfMode.textOnly": "Solo texto", - "dashboard.translate.pdfMode.preserveLayoutDesc": "Mantiene imágenes, tablas y formato. Ideal para PDFs simples.", - "dashboard.translate.pdfMode.textOnlyDesc": "Traduce todo el texto perfectamente. Salida limpia, sin problemas de diseño.", - "dashboard.translate.pipeline.upload": "Subir", - "dashboard.translate.pipeline.analyze": "Analizar", - "dashboard.translate.pipeline.translate": "Traducción", - "dashboard.translate.pipeline.rebuild": "Reconstruir", - "dashboard.translate.pipeline.finalize": "Finalizar", - "dashboard.translate.progress.processingFallback": "Procesando…", - "dashboard.translate.progress.connectionLost": "Conexión perdida. Reintentando…", - "dashboard.translate.progress.failedTitle": "Traducción fallida", - "dashboard.translate.error.unexpected": "Ocurrió un error inesperado. Inténtelo de nuevo.", - "dashboard.translate.error.noResult": "La traducción no produjo resultados. Verifique que el documento contenga texto e intente de nuevo o elija otro motor.", - "dashboard.translate.error.apiKey": "Clave API no válida o faltante. Contacte al administrador para configurar las claves.", - "dashboard.translate.error.quota": "Límite de uso alcanzado. Intente de nuevo en unos minutos o elija otro motor.", - "dashboard.translate.error.timeout": "La conexión al servicio de traducción expiró. Verifique su red e intente de nuevo.", - "dashboard.translate.error.sessionExpired": "Sesión expirada. Haga clic en Reintentar para reiniciar la traducción.", - "dashboard.translate.error.empty": "El documento parece vacío o no contiene texto traducible (¿PDF escaneado?).", - "dashboard.translate.error.unsupported": "Formato de archivo no compatible o archivo dañado.", - "dashboard.translate.error.connection": "Conexión perdida. Verifique su red e intente de nuevo.", - "dashboard.translate.error.generic": "Traducción fallida: {detail}", - "dashboard.translate.error.title": "Traducción fallida", - "dashboard.translate.retry": "Reintentar traducción", - "dashboard.translate.newFile": "Nuevo archivo", - "dashboard.translate.modeAI": "Modo IA", - "dashboard.translate.modeClassic": "Modo Clásico", - "dashboard.translate.glossaryLLMHint": "Glosarios disponibles en modo IA", - "dashboard.translate.submitting": "Enviando...", - "dashboard.translate.submit": "Iniciar traducción", - "dashboard.translate.noFile": "Suba un archivo primero", - "dashboard.translate.noTargetLang": "Seleccione un idioma de destino", - "glossaries.yourGlossaries": "Tus glosarios", - "glossaries.title": "Glosarios y Contexto", - "glossaries.description": "Gestiona tus glosarios e instrucciones de contexto para traducciones más precisas.", - "glossaries.createNew": "Crear nuevo", - "glossaries.empty": "Sin glosarios", - "glossaries.emptyDesc": "Crea tu primer glosario o carga un preset profesional arriba", - "glossaries.defineTerms": "términos", - "glossaries.aboutTitle": "Sobre los glosarios", - "glossaries.aboutDesc": "Los glosarios te permiten definir traducciones exactas para términos específicos. Al traducir, los términos del glosario garantizan traducciones consistentes y precisas.", - "glossaries.aboutFormat": "Cada término tiene una palabra fuente y traducciones en varios idiomas. Selecciona un glosario en la página de traducción para aplicarlo.", - "glossaries.toast.created": "Glosario creado", - "glossaries.toast.createdDesc": "El glosario \"{name}\" ha sido creado.", - "glossaries.toast.imported": "Glosario importado", - "glossaries.toast.importedDesc": "El glosario \"{name}\" ha sido importado.", - "glossaries.toast.updated": "Glosario actualizado", - "glossaries.toast.updatedDesc": "El glosario \"{name}\" ha sido actualizado.", - "glossaries.toast.deleted": "Glosario eliminado", - "glossaries.toast.deletedDesc": "El glosario ha sido eliminado.", - "glossaries.toast.error": "Error", - "glossaries.toast.errorCreate": "Error al crear el glosario", - "glossaries.toast.errorImport": "Error al importar el glosario", - "glossaries.toast.errorUpdate": "Error al actualizar el glosario", - "glossaries.toast.errorDelete": "Error al eliminar el glosario", - "glossaries.dialog.title": "Nuevo glosario", - "glossaries.dialog.description": "Crea un glosario para tus traducciones", - "glossaries.dialog.nameLabel": "Nombre", - "glossaries.dialog.namePlaceholder": "Mi glosario", - "glossaries.dialog.tabTemplates": "Plantillas", - "glossaries.dialog.tabFile": "Archivo", - "glossaries.dialog.tabManual": "Manual", - "glossaries.dialog.cancel": "Cancelar", - "glossaries.dialog.creating": "Creando…", - "glossaries.dialog.importing": "Importando…", - "glossaries.dialog.importBtn": "Importar", - "glossaries.dialog.selectPrompt": "Seleccionar", - "glossaries.dialog.createBtn": "Crear", - "glossaries.dialog.createEmpty": "Crear vacío", - "glossaries.dialog.terms": "términos", - "glossaries.dialog.templatesDesc": "Elige una plantilla predefinida", - "glossaries.dialog.templatesEmpty": "No hay plantillas disponibles", - "glossaries.dialog.dropTitle": "Arrastra un archivo CSV aquí", - "glossaries.dialog.dropOr": "o", - "glossaries.dialog.dropFormats": "CSV, TSV, TXT", - "glossaries.termEditor.addTerm": "Añadir término", - "glossaries.termEditor.maxReached": "Se ha alcanzado el máximo de {max} términos por glosario.", - "glossaries.dialog.formatTitle": "Formato", - "glossaries.dialog.formatDesc": "origen,destino (uno por línea)", - "glossaries.dialog.formatNote": "Se ignora la primera línea si se detecta encabezado", - "glossaries.dialog.errorFormat": "Formato no compatible", - "glossaries.dialog.errorSize": "Archivo demasiado grande", - "glossaries.dialog.errorEmpty": "Archivo vacío", - "glossaries.dialog.errorRead": "Error de lectura", - "glossaries.dialog.parsing": "Analizando…", - "glossaries.dialog.termsImported": "términos importados", - "glossaries.dialog.changeFile": "Cambiar archivo", - "glossaries.dialog.retry": "Reintentar", - "glossaries.edit.title": "Modifier le glossaire", - "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", - "glossaries.edit.nameLabel": "Nom du glossaire", - "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", - "glossaries.edit.sourceLang": "Langue source", - "glossaries.edit.targetLang": "Langue cible", - "glossaries.edit.termsLabel": "Termes ({count} valides)", - "glossaries.edit.exportCsv": "Exporter CSV", - "glossaries.edit.importCsv": "Importer CSV", - "glossaries.edit.cancel": "Annuler", - "glossaries.edit.saving": "Enregistrement...", - "glossaries.edit.saveChanges": "Enregistrer les modifications", - "glossaries.edit.importFailedTitle": "Échec de l'importation", - "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", - "glossaries.edit.importSuccessTitle": "Importation réussie", - "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", - "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", - "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", - "glossaries.delete.title": "Supprimer le glossaire", - "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", - "glossaries.delete.warning": "Cette action est irréversible", - "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", - "glossaries.delete.cancel": "Annuler", - "glossaries.delete.deleting": "Suppression...", - "glossaries.delete.deleteBtn": "Supprimer", - "glossaries.upgrade.title": "Glossaires", - "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", - "glossaries.upgrade.feature1": "Créez plusieurs glossaires", - "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", - "glossaries.upgrade.feature3": "Importez/exportez via CSV", - "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", - "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", - "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", - "glossaries.upgrade.proLabel": "Pro", - "glossaries.upgrade.upgradeBtn": "Passer à Pro", - "glossaries.loading": "Chargement...", - "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", - "glossaries.howItWorks.step1Title": "Configurez ici", - "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", - "glossaries.howItWorks.step2Title": "Activez dans Traduire", - "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", - "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", - "glossaries.howItWorks.goToTranslate": "Aller à Traduire", - "glossaries.status.unsaved": "Non enregistré", - "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", - "glossaries.status.inactive": "Inactif", - "glossaries.instructions.whatForBold": "À quoi ça sert ?", - "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", - "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", - "glossaries.instructions.charCount": "{count} caractères", - "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", - "glossaries.instructions.clearAll": "Tout effacer", - "glossaries.instructions.saving": "Enregistrement…", - "glossaries.instructions.saved": "Enregistré", - "glossaries.presets.whatForBold": "À quoi ça sert ?", - "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", - "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", - "glossaries.presets.creating": "Création…", - "glossaries.presets.alreadyImported": "Déjà importé", - "glossaries.presets.it.title": "IT / Logiciel", - "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", - "glossaries.presets.legal.title": "Juridique / Contrats", - "glossaries.presets.legal.desc": "Droit des affaires, contentieux", - "glossaries.presets.medical.title": "Médical / Santé", - "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", - "glossaries.presets.finance.title": "Finance / Comptabilité", - "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", - "glossaries.presets.marketing.title": "Marketing / Publicité", - "glossaries.presets.marketing.desc": "Digital, branding, analytics", - "glossaries.presets.hr.title": "RH / Ressources Humaines", - "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", - "glossaries.presets.scientific.title": "Scientifique / Recherche", - "glossaries.presets.scientific.desc": "Publications, thèses, articles", - "glossaries.presets.ecommerce.title": "E-commerce / Vente", - "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", - "glossaries.grid.title": "Vos", - "glossaries.grid.titleHighlight": "glossaires", - "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", - "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", - "glossaries.grid.activeTranslation": "Traduction active :", - "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", - "glossaries.badge.compatible": "Compatible", - "glossaries.badge.otherTarget": "Autre cible", - "glossaries.card.editTerms": "Modifier les termes", - "glossaries.card.created": "Creado", - "glossaries.card.term": "término", - "glossaries.card.delete": "Supprimer", - "glossaries.grid.searchPlaceholder": "Search a glossary…", - "glossaries.grid.noResults": "No results for this search.", - "glossaries.detail.backToList": "Back to glossaries", - "glossaries.detail.save": "Save", - "glossaries.detail.savedTitle": "Saved", - "glossaries.detail.savedDesc": "The glossary has been updated.", - "glossaries.detail.settingsTitle": "Settings", - "glossaries.detail.sourceLang": "Source language", - "glossaries.detail.targetLang": "Target language", - "glossaries.detail.termsTitle": "Terms", - "glossaries.detail.terms": "terms", - "glossaries.detail.searchTerms": "Filter…", - "glossaries.detail.noTerms": "No terms yet.", - "glossaries.detail.addFirstTerm": "Add the first term", - "glossaries.detail.addTerm": "Add a term", - "glossaries.detail.maxReached": "Maximum limit reached", - "glossaries.detail.source": "Source", - "glossaries.detail.target": "Target", - "glossaries.detail.sourcePlaceholder": "source term", - "glossaries.detail.targetPlaceholder": "target term", - "glossaries.detail.csvTitle": "CSV", - "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", - "glossaries.detail.export": "Export", - "glossaries.detail.import": "Import", - "glossaries.detail.dangerTitle": "Danger zone", - "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", - "glossaries.detail.deleteGlossary": "Delete this glossary", - "glossaries.detail.confirmDelete": "Confirm deletion?", - "glossaries.detail.confirm": "Confirm", - "glossaries.detail.cancel": "Cancel", - "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", - "glossaries.detail.sourceLocked": "fixed", - "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", - "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", - "glossaries.detail.notFoundTitle": "Glossary not found", - "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", - "glossaries.detail.maxTermsTitle": "Limit reached", - "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", - "glossaries.detail.importEmptyTitle": "Empty file", - "glossaries.detail.importEmptyDesc": "No terms detected in this file.", - "glossaries.detail.importedTitle": "Imported", - "glossaries.detail.importedDesc": "{count} terms imported.", - "glossaries.detail.importErrorTitle": "Read error", - "glossaries.detail.importErrorDesc": "Unable to read the file.", - "apiKeys.webhook.title": "Intégration Webhook", - "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", - "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", - "apiKeys.webhook.codeParam": "webhook_url", - "translate.mode.label": "Mode de traduction", - "translate.mode.classic": "Classique", - "translate.mode.classicDesc": "Rapide", - "translate.mode.proLlm": "Pro LLM", - "translate.mode.proLlmDesc": "Contextuel", - "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", - "translate.mode.upgradeLink": "Passer à Pro", - "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", - "pricing.nav.back": "Volver", - "pricing.nav.home": "Inicio", - "pricing.nav.mySubscription": "Mi suscripción", - "pricing.header.badge": "Modelos IA actualizados — Marzo 2026", - "pricing.header.title": "Un plan para cada necesidad", - "pricing.header.subtitle": "Traduce tus documentos de Word, Excel y PowerPoint conservando el diseño original. Sin necesidad de clave API.", - "pricing.billing.monthly": "Mensual", - "pricing.billing.yearly": "Anual", - "pricing.plans.free.name": "Gratis", - "pricing.plans.starter.name": "Starter", - "pricing.plans.pro.name": "Pro", - "pricing.plans.business.name": "Business", - "pricing.plans.enterprise.name": "Enterprise", - "pricing.plans.free.description": "Perfecto para descubrir la aplicación", - "pricing.plans.starter.description": "Para particulares y proyectos pequeños", - "pricing.plans.pro.description": "Para profesionales y equipos en crecimiento", - "pricing.plans.business.description": "Para equipos y organizaciones", - "pricing.plans.enterprise.description": "Soluciones a medida para grandes organizaciones", - "pricing.plans.pro.highlight": "El más popular", - "pricing.plans.pro.badge": "POPULAR", - "pricing.plans.enterprise.badge": "BAJO PETICIÓN", - "pricing.plans.free.feat1": "5 documentos / mes", - "pricing.plans.free.feat2": "Hasta 15 páginas por documento", - "pricing.plans.free.feat3": "Traductor de Google incluido", - "pricing.plans.free.feat4": "Todos los idiomas (130+)", - "pricing.plans.free.feat5": "Soporte comunitario", - "pricing.plans.starter.feat1": "50 documentos / mes", - "pricing.plans.starter.feat2": "Hasta 50 páginas por documento", - "pricing.plans.starter.feat3": "Traductor de Google + DeepL", - "pricing.plans.starter.feat4": "Archivos de hasta 10 MB", - "pricing.plans.starter.feat5": "Soporte por correo electrónico", - "pricing.plans.starter.feat6": "Historial de 30 días", - "pricing.plans.pro.feat1": "200 documentos / mes", - "pricing.plans.pro.feat2": "Hasta 200 páginas por documento", - "pricing.plans.pro.feat3": "Traducción IA Esencial", - "pricing.plans.pro.feat4": "Traductor de Google + DeepL", - "pricing.plans.pro.feat5": "Archivos de hasta 25 MB", - "pricing.plans.pro.feat6": "Glosarios personalizados", - "pricing.plans.pro.feat7": "Soporte prioritario", - "pricing.plans.pro.feat8": "Historial de 90 días", - "pricing.plans.business.feat1": "1 000 documentos / mes", - "pricing.plans.business.feat2": "Hasta 500 páginas por documento", - "pricing.plans.business.feat3": "IA Esencial + Premium (Claude Haiku)", - "pricing.plans.business.feat4": "Todos los proveedores de traducción", - "pricing.plans.business.feat5": "Archivos de hasta 50 MB", - "pricing.plans.business.feat6": "Acceso API (10 000 llamadas/mes)", - "pricing.plans.business.feat7": "Webhooks de notificación", - "pricing.plans.business.feat8": "Soporte dedicado", - "pricing.plans.business.feat9": "Historial de 1 año", - "pricing.plans.business.feat10": "Analíticas avanzadas", - "pricing.plans.enterprise.feat1": "Documentos ilimitados", - "pricing.plans.enterprise.feat2": "Todos los modelos de IA (GPT-5, Claude Opus 4.6…)", - "pricing.plans.enterprise.feat3": "Implementación local o en nube dedicada", - "pricing.plans.enterprise.feat4": "SLA 99,9 % garantizado", - "pricing.plans.enterprise.feat5": "Soporte dedicado 24/7", - "pricing.plans.enterprise.feat6": "Marca blanca", - "pricing.plans.enterprise.feat7": "Equipos ilimitados", - "pricing.plans.enterprise.feat8": "Integraciones a medida", - "pricing.card.onRequest": "Bajo petición", - "pricing.card.free": "Gratis", - "pricing.card.perMonth": "/mes", - "pricing.card.billedYearly": "Facturado {price} € / año", - "pricing.card.documents": "Documentos", - "pricing.card.pagesMax": "Páginas máx.", - "pricing.card.aiTranslation": "Traducción IA", - "pricing.card.unlimited": "Ilimitado", - "pricing.card.perMonthStat": "/ mes", - "pricing.card.perDoc": "p / doc", - "pricing.card.aiEssential": "Esencial", - "pricing.card.aiEssentialPremium": "Esencial + Premium", - "pricing.card.aiCustom": "A medida", - "pricing.card.myPlan": "Mi plan", - "pricing.card.managePlan": "Gestionar mi plan", - "pricing.card.startFree": "Empezar gratis", - "pricing.card.contactUs": "Contáctenos", - "pricing.card.choosePlan": "Elegir este plan", - "pricing.card.processing": "Procesando…", - "pricing.comparison.title": "Comparación detallada", - "pricing.comparison.subtitle": "Todo lo incluido en cada plan", - "pricing.comparison.feature": "Característica", - "pricing.comparison.docsPerMonth": "Documentos / mes", - "pricing.comparison.pagesMaxPerDoc": "Páginas máx. / documento", - "pricing.comparison.maxFileSize": "Tamaño máx. de archivo", - "pricing.comparison.googleTranslation": "Traductor de Google", - "pricing.comparison.deepl": "DeepL", - "pricing.comparison.aiEssential": "Traducción IA Esencial", - "pricing.comparison.aiPremium": "Traducción IA Premium", - "pricing.comparison.apiAccess": "Acceso API", - "pricing.comparison.priorityProcessing": "Procesamiento prioritario", - "pricing.comparison.support": "Soporte", - "pricing.comparison.support.community": "Comunidad", - "pricing.comparison.support.email": "Correo electrónico", - "pricing.comparison.support.priority": "Prioritario", - "pricing.comparison.support.dedicated": "Dedicado", - "pricing.comparison.mb": "MB", - "pricing.credits.title": "Créditos adicionales", - "pricing.credits.subtitle": "¿Necesitas más? Compra créditos individuales, sin suscripción.", - "pricing.credits.perPage": "1 crédito = 1 página traducida.", - "pricing.credits.bestValue": "Mejor relación calidad-precio", - "pricing.credits.unit": "créditos", - "pricing.credits.centsPerCredit": "cts / crédito", - "pricing.credits.buy": "Comprar", - "pricing.trust.encryption.title": "Cifrado de extremo a extremo", - "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 en reposo", - "pricing.trust.languages.title": "130+ idiomas", - "pricing.trust.languages.sub": "Incluido árabe, persa, hebreo (RTL)", - "pricing.trust.parallel.title": "Procesamiento en paralelo", - "pricing.trust.parallel.sub": "IA multiproceso ultrarrápida", - "pricing.trust.availability.title": "Disponible 24/7", - "pricing.trust.availability.sub": "Disponibilidad garantizada del 99,9 %", - "pricing.aiModels.title": "Nuestros modelos de IA — Marzo 2026", - "pricing.aiModels.essential.title": "Traducción IA Esencial", - "pricing.aiModels.essential.plan": "Plan Pro", - "pricing.aiModels.essential.descPrefix": "Basado en", - "pricing.aiModels.essential.descSuffix": "— el modelo de IA más rentable de 2026. Calidad comparable a los modelos frontier a una fracción del coste.", - "pricing.aiModels.essential.modelName": "nuestro modelo IA Esencial", - "pricing.aiModels.essential.context": "163K tokens de contexto", - "pricing.aiModels.essential.value": "Excelente relación calidad-precio", - "pricing.aiModels.premium.title": "Traducción IA Premium", - "pricing.aiModels.premium.plan": "Plan Business", - "pricing.aiModels.premium.descPrefix": "Basado en", - "pricing.aiModels.premium.descSuffix": "de Anthropic — preciso en documentos jurídicos, médicos y técnicos complejos.", - "pricing.aiModels.premium.context": "200K tokens de contexto", - "pricing.aiModels.premium.precision": "Máxima precisión", - "pricing.faq.title": "Preguntas frecuentes", - "pricing.faq.q1": "¿Puedo cambiar de plan en cualquier momento?", - "pricing.faq.a1": "Sí. La mejora es inmediata y prorrateada. La bajada se aplica al final del periodo actual.", - "pricing.faq.q2": "¿Qué es la «Traducción IA Esencial»?", - "pricing.faq.a2": "Es nuestro motor de IA. Comprende el contexto de tus documentos, conserva el diseño y maneja términos técnicos mucho mejor que una traducción clásica.", - "pricing.faq.q3": "¿Cuál es la diferencia entre IA Esencial e IA Premium?", - "pricing.faq.a3": "La IA Esencial usa un modelo optimizado (excelente relación calidad-precio). La IA Premium usa Claude 3.5 Haiku de Anthropic, más precisa en documentos jurídicos, médicos y técnicos complejos.", - "pricing.faq.q4": "¿Se conservan mis documentos después de la traducción?", - "pricing.faq.a4": "Los archivos traducidos están disponibles según tu plan (30 días Starter, 90 días Pro, 1 año Business). Están cifrados en reposo y en tránsito.", - "pricing.faq.q5": "¿Qué ocurre si supero mi cuota mensual?", - "pricing.faq.a5": "Puedes comprar créditos adicionales de forma individual o mejorar tu plan. Se te notificará al alcanzar el 80 % de uso.", - "pricing.faq.q6": "¿Hay una prueba gratuita para los planes de pago?", - "pricing.faq.a6": "El plan Gratuito es permanente y no requiere tarjeta. Para los planes Pro y Business, contáctenos para una prueba de 14 días.", - "pricing.faq.q7": "¿Qué formatos de archivo son compatibles?", - "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx) y próximamente PDF. Todos los planes son compatibles con los mismos formatos.", - "pricing.cta.title": "¿Listo para empezar?", - "pricing.cta.subtitle": "Empieza gratis, sin tarjeta de crédito. Mejora tu plan cuando lo necesites.", - "pricing.cta.createAccount": "Crear una cuenta gratuita", - "pricing.cta.login": "Iniciar sesión", - "pricing.toast.demo": "Modo demo — Stripe aún no está configurado. En producción, serías redirigido al pago para activar el plan {planId}.", - "pricing.toast.networkError": "Error de red. Por favor, inténtalo de nuevo.", - "pricing.toast.paymentError": "Error al crear el pago.", - "register.title": "Crear una cuenta", - "register.subtitle": "Empieza a traducir gratis", - "register.error.failed": "Error en el registro", - "register.name.label": "Nombre", - "register.name.placeholder": "Tu nombre", - "register.name.error": "El nombre debe tener al menos 2 caracteres", - "register.email.label": "Correo electrónico", - "register.email.placeholder": "tu@ejemplo.com", - "register.email.error": "Dirección de correo no válida", - "register.password.label": "Contraseña", - "register.password.error": "La contraseña debe tener al menos 8 caracteres, una mayúscula, una minúscula y un dígito", - "register.password.show": "Mostrar contraseña", - "register.password.hide": "Ocultar contraseña", - "register.password.strengthLabel": "Fortaleza:", - "register.password.strength.weak": "Débil", - "register.password.strength.medium": "Media", - "register.password.strength.strong": "Fuerte", - "register.confirmPassword.label": "Confirmar contraseña", - "register.confirmPassword.error": "Las contraseñas no coinciden", - "register.confirmPassword.show": "Mostrar", - "register.confirmPassword.hide": "Ocultar", - "register.submit.creating": "Creando cuenta...", - "register.submit.create": "Crear mi cuenta", - "register.hasAccount": "¿Ya tienes una cuenta?", - "register.login": "Iniciar sesión", - "register.terms.prefix": "Al crear una cuenta, aceptas nuestros", - "register.terms.link": "términos de servicio", - "login.errorTitle": "Login Error", - "login.welcomeBack": "Welcome back", - "login.signInToContinue": "Sign in to continue translating", - "login.email": "Email", - "login.emailPlaceholder": "you@example.com", - "login.password": "Password", - "login.forgotPassword": "Forgot password?", - "login.passwordPlaceholder": "••••••••", - "login.signingIn": "Signing in...", - "login.signIn": "Sign In", - "login.noAccount": "Don't have an account?", - "login.signUpFree": "Sign up for free", - "login.orContinueWith": "o continuar con correo electrónico", - "login.google.connecting": "Conectando…", - "login.google.errorGeneric": "Se ha producido un error con el inicio de sesión de Google.", - "login.google.errorFailed": "Error al iniciar sesión con Google. Inténtalo de nuevo.", - "forgotPassword.enterEmail": "Please enter your email address", - "forgotPassword.error": "An error occurred", - "forgotPassword.title": "Forgot Password", - "forgotPassword.checkEmail": "Check your inbox", - "forgotPassword.subtitle": "Enter your email to receive a reset link", - "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", - "forgotPassword.emailLabel": "Email address", - "forgotPassword.emailPlaceholder": "you@example.com", - "forgotPassword.sending": "Sending...", - "forgotPassword.sendLink": "Send reset link", - "forgotPassword.backToLogin": "Back to login", - "forgotPassword.loading": "Loading...", - "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", - "resetPassword.passwordMismatch": "Passwords do not match", - "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", - "resetPassword.error": "An error occurred", - "resetPassword.invalidLink": "Invalid link", - "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", - "resetPassword.requestNewLink": "Request new link", - "resetPassword.successTitle": "Password reset", - "resetPassword.newPasswordTitle": "New password", - "resetPassword.successSubtitle": "You will be redirected to login", - "resetPassword.subtitle": "Set your new password", - "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", - "resetPassword.newPassword": "New password", - "resetPassword.showPassword": "Show password", - "resetPassword.hidePassword": "Hide password", - "resetPassword.confirmPassword": "Confirm password", - "resetPassword.resetting": "Resetting...", - "resetPassword.resetPassword": "Reset password", - "resetPassword.backToLogin": "Back to login", - "resetPassword.loading": "Loading...", - "common.loading": "Cargando...", - "profile.header.title": "Mi perfil", - "profile.header.subtitle": "Gestiona tu cuenta y preferencias.", - "profile.tabs.account": "Cuenta", - "profile.tabs.subscription": "Suscripción", - "profile.tabs.preferences": "Preferencias", - "profile.account.user": "Usuario", - "profile.account.memberSince": "Miembro desde", - "profile.plan.label": "Plan", - "profile.plan.free": "Gratis", - "profile.plan.starter": "Starter", - "profile.plan.pro": "Pro", - "profile.plan.business": "Business", - "profile.plan.enterprise": "Enterprise", - "profile.plan.pricePerMonth": "{price} €/mes", - "profile.subscription.canceling": "Cancelando", - "profile.subscription.active": "Activa", - "profile.subscription.unknown": "Desconocido", - "profile.subscription.accessUntil": "Acceso hasta", - "profile.subscription.renewalOn": "Renovación el", - "profile.subscription.upgradePlan": "Mejorar a un plan de pago", - "profile.subscription.changePlan": "Cambiar plan", - "profile.subscription.manageBilling": "Gestionar facturación", - "profile.subscription.billingUnavailable": "Portal de facturación no disponible.", - "profile.subscription.billingError": "Error al acceder al portal de facturación.", - "profile.subscription.cancelSuccess": "Suscripción cancelada. Mantienes el acceso hasta el final del periodo.", - "profile.subscription.cancelError": "Error durante la cancelación.", - "profile.subscription.networkError": "Error de red.", - "profile.usage.title": "Uso este mes", - "profile.usage.resetOn": "Reinicio el", - "profile.usage.documents": "Documentos", - "profile.usage.pages": "Páginas", - "profile.usage.extraCredits": "crédito extra", - "profile.usage.extraCreditsPlural": "créditos extra", - "profile.usage.quotaReached": "Cuota alcanzada", - "profile.usage.quotaReachedDesc": "Mejora a un plan superior para continuar.", - "profile.usage.unlockMore": "Desbloquea más traducciones con un plan de pago.", - "profile.usage.viewPlans": "Ver planes", - "profile.usage.includedInPlan": "Incluido en tu plan", - "profile.danger.title": "Zona de peligro", - "profile.danger.description": "La cancelación surte efecto al final de tu periodo actual. Mantienes el acceso hasta esa fecha.", - "profile.danger.confirm": "¿Estás seguro? Esta acción no se puede deshacer.", - "profile.danger.confirmCancel": "Confirmar cancelación", - "profile.danger.cancelSubscription": "Cancelar mi suscripción", - "profile.danger.keep": "No, mantener", - "profile.prefs.interfaceLang": "Idioma de la interfaz", - "profile.prefs.interfaceLangDesc": "El idioma se detecta automáticamente según tu navegador. Puedes cambiarlo manualmente.", - "profile.prefs.defaultTargetLang": "Idioma de destino predeterminado", - "profile.prefs.selectLanguage": "Seleccionar un idioma", - "profile.prefs.defaultTargetLangDesc": "Este idioma se preseleccionará para tus traducciones.", - "profile.prefs.save": "Guardar", - "profile.prefs.theme": "Tema", - "profile.prefs.themeDesc": "Elige la apariencia de la interfaz", - "profile.prefs.cache": "Caché", - "profile.prefs.cacheDesc": "Borrar la caché local puede solucionar algunos problemas de visualización.", - "profile.prefs.clearing": "Borrando...", - "profile.prefs.clearCache": "Borrar caché", - "settings.title": "Configuración", - "settings.subtitle": "Configuración general de la aplicación", - "settings.formats.title": "Formatos compatibles", - "settings.formats.subtitle": "Tipos de documentos que puedes traducir", - "settings.formats.formulas": "Fórmulas", - "settings.formats.styles": "Estilos", - "settings.formats.images": "Imágenes", - "settings.formats.headers": "Encabezados", - "settings.formats.tables": "Tablas", - "settings.formats.slides": "Diapositivas", - "settings.formats.notes": "Notas", - "settings.cache.title": "Caché", - "settings.cache.desc": "Borrar la caché local puede solucionar algunos problemas de visualización.", - "settings.cache.clearing": "Borrando...", - "settings.cache.clear": "Borrar caché", - "services.title": "Proveedores de traducción", - "services.subtitle": "Los proveedores están configurados por el administrador. Puedes ver cuáles están disponibles para tu cuenta.", - "services.loading": "Cargando proveedores...", - "services.noProviders": "No hay proveedores configurados actualmente. Contacta a tu administrador.", - "services.classic": "Traducción clásica", - "services.llmPro": "LLM · Contextual (Pro)", - "services.available": "Disponible", - "services.model": "Modelo", - "services.adminOnly.title": "La configuración de proveedores es solo para administradores", - "services.adminOnly.desc": "Las claves API, la selección de modelos y la activación de proveedores son gestionadas exclusivamente por el administrador en el panel de administración. Nunca necesitas introducir una clave API.", - "apiKeys.title": "Claves API", - "apiKeys.subtitle": "Gestiona tus claves API para el acceso programático a la API de traducción.", - "apiKeys.loading": "Cargando...", - "apiKeys.sectionTitle": "API y automatización", - "apiKeys.sectionDesc": "Genera y gestiona tus claves API para flujos de automatización", - "apiKeys.keysUsed": "{total} de {max} claves usadas", - "apiKeys.maxReached": "Máximo de claves alcanzado. Revoca una clave para generar una nueva.", - "apiKeys.canGenerate": "Puedes generar {count} clave más", - "apiKeys.canGeneratePlural": "Puedes generar {count} claves más", - "apiKeys.generateNew": "Generar nueva clave", - "apiKeys.keyRevoked": "Clave revocada", - "apiKeys.keyRevokedDesc": "La clave API ha sido revocada correctamente.", - "apiKeys.keyNotFound": "Clave no encontrada", - "apiKeys.keyNotFoundDesc": "La clave API ya no existe. Puede que ya haya sido revocada.", - "apiKeys.error": "Error", - "apiKeys.revokeError": "Error al revocar la clave API. Inténtalo de nuevo.", - "apiKeys.limitReached": "Límite alcanzado", - "apiKeys.limitReachedDesc": "Has alcanzado el máximo de 10 claves API. Revoca una clave existente para generar una nueva.", - "apiKeys.proRequired": "Función Pro requerida", - "apiKeys.proRequiredDesc": "Las claves API son una función Pro. Mejora tu cuenta.", - "apiKeys.generateError": "Error al generar la clave API. Inténtalo de nuevo.", - "apiKeys.upgrade.title": "Claves API", - "apiKeys.upgrade.subtitle": "Automatiza tus traducciones con acceso API", - "apiKeys.upgrade.feat1": "Genera claves API ilimitadas", - "apiKeys.upgrade.feat2": "Automatiza la traducción de documentos", - "apiKeys.upgrade.feat3": "Notificaciones por webhook", - "apiKeys.upgrade.feat4": "Modos de traducción LLM", - "apiKeys.upgrade.proFeature": "Las claves API son una función {pro}. Mejora para desbloquear la automatización API.", - "apiKeys.upgrade.pro": "Pro", - "apiKeys.upgrade.cta": "Mejorar a Pro", - "apiKeys.dialog.maxTitle": "Máximo de claves alcanzado", - "apiKeys.dialog.maxDesc": "Has alcanzado el máximo de 10 claves API. Revoca una clave existente antes de generar una nueva.", - "apiKeys.dialog.close": "Cerrar", - "apiKeys.dialog.generated": "¡Clave API generada!", - "apiKeys.dialog.generatedDesc": "Tu nueva clave API ha sido creada. Cópiala ahora, no se volverá a mostrar.", - "apiKeys.dialog.important": "Importante:", - "apiKeys.dialog.importantDesc": "Esta es la única vez que verás esta clave. Guárdala de forma segura.", - "apiKeys.dialog.apiKey": "Clave API", - "apiKeys.dialog.name": "Nombre:", - "apiKeys.dialog.done": "Listo", - "apiKeys.dialog.copied": "Ya he copiado la clave", - "apiKeys.dialog.generateTitle": "Generar nueva clave API", - "apiKeys.dialog.generateDesc": "Crea una nueva clave API para el acceso programático a la API de traducción.", - "apiKeys.dialog.keyName": "Nombre de la clave (opcional)", - "apiKeys.dialog.keyNamePlaceholder": "p.ej., Producción, Staging", - "apiKeys.dialog.keyNameHint": "Un nombre descriptivo para identificar esta clave más tarde.", - "apiKeys.dialog.nameTooLong": "El nombre debe tener {max} caracteres o menos", - "apiKeys.dialog.nameInvalid": "El nombre solo puede contener letras, números, espacios, guiones y guiones bajos", - "apiKeys.dialog.cancel": "Cancelar", - "apiKeys.dialog.generating": "Generando...", - "apiKeys.dialog.generate": "Generar clave", - "apiKeys.table.name": "Nombre", - "apiKeys.table.prefix": "Prefijo", - "apiKeys.table.created": "Creada", - "apiKeys.table.lastUsed": "Último uso", - "apiKeys.table.never": "Nunca", - "apiKeys.table.actions": "Acciones", - "apiKeys.table.revoke": "Revocar", - "apiKeys.table.copyPrefix": "Copiar prefijo de la clave", - "apiKeys.table.revokeKey": "Revocar clave", - "apiKeys.revokeDialog.title": "Revocar clave API", - "apiKeys.revokeDialog.desc": "¿Estás seguro de que quieres revocar la clave \"{name}\"? Esta acción no se puede deshacer.", - "apiKeys.revokeDialog.confirm": "Sí, revocar", - "apiKeys.revokeDialog.cancel": "Cancelar", - "context.proTitle": "Función Pro", - "context.proDesc": "El contexto y los glosarios profesionales están disponibles con los planes Pro, Business y Enterprise. Proporcionan traducciones más precisas mediante instrucciones y vocabulario específico de tu dominio.", - "context.viewPlans": "Ver planes", - "context.title": "Contexto y glosario", - "context.subtitle": "Mejora la calidad de traducción con instrucciones y vocabulario específico de tu dominio.", - "context.presets.title": "Glosarios profesionales", - "context.presets.desc": "Carga un glosario completo con instrucciones y terminología especializada", - "context.instructions.title": "Instrucciones de contexto", - "context.instructions.desc": "Instrucciones que la IA seguirá durante la traducción", - "context.instructions.placeholder": "P.ej.: Traduces documentos técnicos de climatización. Usa terminología de ingeniería precisa...", - "context.glossary.title": "Glosario técnico", - "context.glossary.desc": "Formato: origen=destino (uno por línea). Los glosarios cargados mediante preset son editables.", - "context.glossary.terms": "términos en el glosario", - "context.clearAll": "Borrar todo", - "context.saving": "Guardando...", - "context.save": "Guardar", - "translate.glossary.title": "Glosario", - "translate.glossary.select": "Seleccionar glosario", - "translate.glossary.none": "Ninguno", - "translate.glossary.terms": "términos", - "translate.glossary.proOnly": "Actualiza a Pro para usar glosarios", - "translate.glossary.myGlossaries": "Mis glosarios", - "translate.glossary.fromTemplate": "Crear desde plantilla", - "translate.glossary.noGlossaryForPair": "Sin glosario para", - "translate.glossary.noGlossaries": "Sin glosarios", - "translate.glossary.loading": "Cargando...", - "translate.glossary.classicMode": "Motor neutro sin glosario (solo IA)", - "translate.glossary.selectPlaceholder": "Seleccionar un glosario...", - "translate.glossary.multilingual": "MULTILINGÜE", - "translate.glossary.noGlossaryAvailable": "Ningún glosario disponible", - "translate.glossary.filterByLang": "Filtrar por idioma", - "translate.glossary.active": "Activo", - "translate.glossary.inactive": "Inactivo", - "translate.glossary.availableTemplates": "Plantillas disponibles", - "translate.glossary.importing": "Importando...", - "translate.glossary.imported": "(Importado)", - "translate.glossary.noGlossaryForSource": "Ningún glosario ni plantilla para el idioma de origen", - "translate.glossary.createGlossary": "Crear un glosario", - "translate.glossary.showAll": "Mostrar todos los glosarios", - "translate.glossary.activePreview": "Vista previa de correspondencias activas:", - "translate.glossary.total": "en total", - "translate.glossary.moreTerms": "términos más", - "translate.glossary.noTerms": "Ningún término en este glosario.", - "translate.glossary.sourceTerm": "Término fuente", - "translate.glossary.translation": "Traducción", - "translate.glossary.addTerm": "Añadir término", - "translate.glossary.disabledMode": "Motor neutro sin glosario aplicado", - "translate.glossary.addTermError": "Error al añadir el término", - "translate.glossary.networkError": "Error de red", - "translate.glossary.importFailed": "Error al importar ({status})", - "translate.glossary.helpText": "El glosario fuerza la traducción de términos precisos. Elija un glosario cuyo idioma de origen coincida con el idioma original de su documento.", - "translate.glossary.sourceWarning": "Atención: Este glosario usa el idioma de origen", - "translate.glossary.sourceWarningBut": "pero su documento está configurado en", - "translate.glossary.targetWarning": "Incompatibilidad de destino: Este glosario está diseñado para traducir a", - "translate.glossary.targetWarningBut": "pero su documento tiene como destino", - "translate.glossary.targetWarningEnd": "Los términos pueden no ser relevantes.", - "context.presets.createGlossary": "Crear glosario", - "context.presets.created": "Glosario creado", - "context.presets.createdDesc": "El glosario \"{name}\" ha sido creado con {count} términos.", - "context.presets.hint": "Haz clic en un preset para crear un glosario con términos específicos del dominio. Gestiona tus glosarios en la sección de Glosarios.", - "context.glossary.manage": "Gestionar glosarios", - "context.saved": "Guardado", - "context.savedDesc": "Tus instrucciones de contexto se han guardado.", - "admin.login.title": "Administración", - "admin.login.required": "Inicio de sesión requerido", - "admin.login.password": "Contraseña de administrador", - "admin.login.connecting": "Conectando...", - "admin.login.access": "Acceder al panel de administración", - "admin.login.restricted": "Restringido a administradores", - "admin.layout.checking": "Verificando autenticación...", - "admin.dashboard.title": "Panel de Administración", - "admin.dashboard.subtitle": "Panel de control del administrador", - "admin.dashboard.refresh": "Actualizar", - "admin.dashboard.refreshTooltip": "Actualizar datos del panel", - "admin.dashboard.config": "Configuración del sistema", - "admin.dashboard.maxFileSize": "Tamaño máximo de archivo:", - "admin.dashboard.translationService": "Servicio de traducción:", - "admin.dashboard.formats": "Formatos:", - "admin.nav.dashboard": "Dashboard", - "admin.nav.users": "Usuarios", - "admin.nav.pricing": "Precios y Stripe", - "admin.nav.providers": "Proveedores", - "admin.nav.system": "Sistema", - "admin.nav.logs": "Registros", - "admin.users.title": "Gestión de Usuarios", - "admin.users.subtitle": "Ver y gestionar cuentas de usuario", - "admin.users.planUpdated": "Plan actualizado", - "admin.users.planChanged": "El plan se ha cambiado a \"{plan}\" correctamente.", - "admin.users.unknownError": "Error desconocido", - "admin.users.error": "Error", - "admin.users.planUpdateError": "No se pudo actualizar el plan: {message}", - "admin.users.noKeys": "Sin claves", - "admin.users.noKeysDesc": "Este usuario no tiene claves API activas.", - "admin.users.keysRevoked": "Claves revocadas", - "admin.users.keysRevokedDesc": "{count} clave(s) API revocada(s) correctamente.", - "admin.users.revokeError": "No se pudieron revocar las claves: {message}", - "admin.users.retry": "Reintentar", - "admin.system.title": "Sistema", - "admin.system.subtitle": "Supervisar el estado del sistema y gestionar recursos", - "admin.system.quotas": "Cuotas de traducción", - "admin.system.resetQuotas": "Restablecer cuotas mensuales", - "admin.system.resetting": "Restableciendo...", - "admin.system.reset": "Restablecer", - "admin.system.allOperational": "Todos los sistemas operativos", - "admin.system.issuesDetected": "Problemas detectados en el sistema", - "admin.system.waitingData": "Esperando datos...", - "admin.system.purging": "Purgando...", - "admin.system.clean": "Limpiar", - "admin.system.purge": "Purgar", - "memento.title": "Descubre Momento", - "memento.slogan": "Momento no es solo una aplicación de notas. Es un ecosistema inteligente que conecta, analiza y desarrolla tus ideas en tiempo real usando 6 agentes de IA y búsqueda semántica avanzada.", - "memento.ctaFree": "Empezar gratis", - "memento.ctaMore": "Saber más", - "common.backToHome": "Volver al inicio", - "dashboard.topbar.interfaceLabel": "Interfaz de traducción", - "dashboard.topbar.premiumAccess": "Acceso Premium", - "landing.hero.contextEngine": "Traducción detectada: Término técnico de mantenimiento para sistemas HVAC...", - "landing.hero.liveAnalysis": "Análisis en vivo", - "landing.hero.termsDetected": "términos detectados", - "landing.steps.process": "PROCESO", - "landing.translate.newProject": "Nuevo proyecto", - "landing.translate.title": "Traducir un documento", - "landing.translate.subtitle": "Importa un archivo y elige el idioma de destino", - "landing.translate.sourceDocument": "Documento fuente", - "landing.translate.configuration": "Configuración", - "landing.translate.sourceLang": "Idioma de origen", - "landing.translate.targetLang": "Idioma de destino", - "landing.translate.provider": "Proveedor", - "landing.translate.startTranslation": "Iniciar traducción", - "landing.translate.zeroRetention": "Retención cero", - "landing.translate.filesDeleted": "Archivos eliminados tras el procesamiento", - "landing.translate.dropHere": "Arrastra y suelta aquí", - "landing.translate.supportedFormats": "Archivos DOCX, XLSX, PPTX o PDF compatibles", - "landing.translate.aiAnalysis": "Análisis IA Activo", - "landing.translate.processing": "Procesando", - "landing.translate.preservingLayout": "Tu diseño se está preservando", - "layout.nav.apiAccess": "Acceso API", - "layout.footer.terms": "Términos", - "layout.footer.privacy": "Privacidad", - "fileUploader.uploadDocument": "Subir documento", - "fileUploader.uploadDesc": "Arrastre y suelte o haga clic para seleccionar un archivo (Excel, Word, PowerPoint)", - "fileUploader.dropHere": "Suelta tu archivo aquí…", - "fileUploader.dragAndDrop": "Arrastra y suelta tu documento aquí", - "fileUploader.orClickBrowse": "o haz clic para examinar", - "fileUploader.preview": "Vista previa", - "fileUploader.translationOptions": "Opciones de traducción", - "fileUploader.configureSettings": "Configura los ajustes de traducción", - "fileUploader.targetLanguage": "Idioma de destino", - "fileUploader.selectLanguage": "Seleccionar idioma", - "fileUploader.translationProvider": "Proveedor de traducción", - "fileUploader.selectProvider": "Seleccionar proveedor", - "fileUploader.advancedOptions": "Opciones avanzadas", - "fileUploader.translateImages": "Traducir imágenes", - "fileUploader.translating": "Traduciendo…", - "fileUploader.translateDocument": "Traducir documento", - "fileUploader.processing": "Procesando…", - "fileUploader.translationError": "Error de traducción", - "fileUploader.translationComplete": "¡Traducción completa!", - "fileUploader.translationCompleteDesc": "Su documento se ha traducido correctamente conservando todo el formato.", - "fileUploader.download": "Descargar documento traducido", - "fileUploader.webgpuUnsupported": "WebGPU no es compatible con este navegador. Use Chrome 113+ o Edge 113+.", - "fileUploader.webllmNotLoaded": "Modelo WebLLM no cargado. Vaya a Configuración > Servicios de traducción para cargar un modelo.", - "fileUploader.extracting": "Extrayendo textos del documento…", - "fileUploader.noTranslatable": "No se encontró texto traducible en el documento", - "fileUploader.foundTexts": "Se encontraron {count} textos para traducir", - "fileUploader.translatingItem": "Traduciendo {current}/{total}: «{preview}»", - "fileUploader.reconstructing": "Reconstruyendo documento…", - "fileUploader.translatingLocally": "Traduciendo localmente con WebLLM…", - "checkout.activating": "Activando…", - "checkout.activatingDesc": "Estamos actualizando su suscripción, espere.", - "checkout.paymentConfirmed": "¡Pago confirmado!", - "checkout.subscriptionActivated": "¡Suscripción activada!", - "checkout.planActivated": "¡Plan {plan} activado!", - "checkout.redirectingToProfile": "Redirigiendo a su perfil…", - "checkout.paymentReceived": "Pago recibido", - "checkout.redirecting": "Redirigiendo…", - "checkout.syncError": "Error de sincronización", - "checkout.networkError": "Error de red. Su pago está confirmado — recargue su perfil.", - "dashboard.checkoutSyncError": "Error al sincronizar el pago.", - "dashboard.networkRefresh": "Error de red. Por favor, actualice la página.", - "dashboard.continueToTranslate": "Continuar a la traducción", - "langSelector.search": "Buscar…", - "langSelector.noResults": "Sin resultados", - "langSelector.source": "Origen", - "langSelector.target": "Destino", - "langSelector.swap": "Intercambiar", - "translateComplete.highQuality": "Alta calidad", - "translateComplete.segments": "Segmentos", - "translateComplete.characters": "Caracteres", - "translateComplete.confidence": "Confianza", - "providerTheme.deepseek.badge": "Esencial", - "providerTheme.deepseek.subBadge": "Técnico y económico", - "providerTheme.deepseek.desc": "Traducción ultraprecisa y económica, ideal para documentos técnicos y código.", - "providerTheme.openai.badge": "Premium", - "providerTheme.openai.subBadge": "Alta fidelidad", - "providerTheme.openai.desc": "El estándar global de IA. Máxima coherencia textual y respeto estricto del estilo.", - "providerTheme.minimax.badge": "Avanzada", - "providerTheme.minimax.subBadge": "Rendimiento", - "providerTheme.minimax.desc": "Velocidad de ejecución increíble y excelente comprensión de estructuras complejas.", - "providerTheme.openrouter.badge": "Exprés", - "providerTheme.openrouter.subBadge": "Multi-modelo", - "providerTheme.openrouter.desc": "Acceso unificado a los mejores modelos de código abierto optimizados para traducción.", - "providerTheme.openrouter_premium.badge": "Ultra", - "providerTheme.openrouter_premium.subBadge": "Contexto máximo", - "providerTheme.openrouter_premium.desc": "Asistido por modelos de última generación (GPT-4o, Claude Sonnet 4.6) para documentos largos.", - "providerTheme.zai.badge": "Especializada", - "providerTheme.zai.subBadge": "Finanzas y Derecho", - "providerTheme.zai.desc": "Modelo ajustado para terminologías empresariales exigentes (legal, finanzas).", - "providerTheme.default.badge": "Moderno", - "providerTheme.default.subBadge": "Razonamiento IA", - "providerTheme.default.desc": "Traducción por modelo de lenguaje grande (LLM) con análisis semántico avanzado.", - "providerTheme.classic.google.label": "Google Traductor", - "providerTheme.classic.google.desc": "Traducción ultrarrápida que cubre más de 130 idiomas. Recomendado para flujos generales.", - "providerTheme.classic.deepl.label": "DeepL Pro", - "providerTheme.classic.deepl.desc": "Traducción de alta precisión conocida por su fluidez y formulaciones naturales.", - "providerTheme.classic.google_cloud.label": "Google Cloud API", - "providerTheme.classic.google_cloud.desc": "Motor en la nube profesional optimizado para procesar grandes volúmenes de documentos.", - "providerSelector.noClassic": "No hay traductor estándar disponible.", - "providerSelector.noLlm": "Ningún modelo de IA configurado.", - "providerSelector.costOne": "Costo: 1 crédito por página", - "providerSelector.costFive": "Costo: 5 créditos por página (Factor Premium)", - "providerSelector.unlockContextual": "Desbloquee la traducción contextual premium para sus documentos completos.", - "translate.header.processing": "Procesamiento en curso", - "translate.header.aiActive": "Análisis IA activo", - "translate.header.aiActiveDesc": "Su diseño se está preservando por nuestro motor contextual.", - "translate.header.completed": "Completado", - "translate.header.completedTitle": "Traducción completada", - "translate.header.proSpace": "Espacio Pro", - "translate.header.translateDoc": "Traducir un documento", - "translate.header.translateDocDesc": "Conserve el diseño original con nuestro motor de traducción de ultra alta fidelidad.", - "translate.upload.nativeFormat": "Formato nativo", - "translate.fileType.word": "Word (.docx)", - "translate.fileType.excel": "Excel (.xlsx)", - "translate.fileType.slides": "Diapositivas (.pptx)", - "translate.fileType.pdf": "PDF (.pdf)", - "translate.startTranslation": "Iniciar traducción", - "translate.submit": "Enviando…", - "translate.chooseTargetLang": "Por favor, elija un idioma de destino", - "translate.pleaseLoadFile": "Por favor, suba un archivo primero", - "translate.contextEngineActive": "Motor contextual activo", - "translate.phase1": "Fase 1: Inicialización", - "translate.phase2": "Fase 2: Reconstrucción contextual", - "translate.stat.segments": "segmentos", - "translate.stat.precision": "precisión", - "translate.stat.speedLabel": "velocidad", - "translate.stat.turbo": "Turbo", - "translate.stat.time": "tiempo", - "translate.complete.masterQuality": "✓ Calidad maestra", - "translate.download": "Descargar", - "translate.newTranslation": "+ Nueva traducción", - "translate.failedTitle": "Error de traducción", - "translate.retry": "Reintentar", - "translate.uploadAnother": "Subir otro archivo", - "translate.monitor": "Monitor IA", - "translate.summary": "Resumen", - "translate.cancelProcess": "⟳ Cancelar el proceso", - "translate.layoutIntegrity": "Integridad del diseño", - "translate.secureHundred": "100% SEGURO", - "translate.okHundred": "100% OK", - "translate.preserveLayout": "Conservar diseño", - "translate.preserveLayoutDesc": "Conservar el diseño", - "translate.textOnly": "Solo texto", - "translate.textOnlyDesc": "Traducción rápida solo de texto", - "translate.unavailableStandard": "No disponible en modo Estándar (solo IA)", - "apiKeys.noKeysGenerated": "No hay claves generadas", - "apiKeys.copied": "¡Copiado!", - "services.fallback.google.label": "Google Traductor", - "services.fallback.google.desc": "Traducción rápida, más de 130 idiomas", - "settings.formats.excel.name": "Excel", - "settings.formats.word.name": "Word", - "settings.formats.powerpoint.name": "PowerPoint", - "pricing.dashboard": "Panel", - "pricing.okSymbol": "✓", - "pricing.errSymbol": "✕", - }, - // ═══════════════════════════════════════════════════════════════ - // GERMAN (de) - // ═══════════════════════════════════════════════════════════════ - de: { - "auth.brandName": "Wordly", - "dashboard.nav.translate": "Übersetzen", - "dashboard.nav.profile": "Mein Profil", - "dashboard.nav.settings": "Einstellungen", - "dashboard.nav.context": "Kontext", - "dashboard.nav.services": "Dienste", - "dashboard.nav.apiKeys": "API-Schlüssel", - "dashboard.nav.glossaries": "Glossare", - "dashboard.header.title": "Dashboard", - "dashboard.header.subtitle": "Verwalten Sie Ihre Übersetzungen", - "dashboard.header.toggleMenu": "Menü", - "dashboard.header.profileTitle": "Mein Profil", - "dashboard.sidebar.theme": "Design", - "dashboard.sidebar.signOut": "Abmelden", - "dashboard.sidebar.backHome": "Zurück zur Startseite", - "dashboard.sidebar.upgradeToPro": "Auf Pro upgraden →", - "cookieConsent.title": "Cookies auf Wordly", - "cookieConsent.description": "Wir verwenden essenzielle Cookies, damit die App funktioniert (Sitzung, Sicherheit, Sprache). Mit Ihrer Erlaubnis verwenden wir auch optionale Cookies zur Verkehrsmessung und Produktverbesserung.", - "cookieConsent.acceptAll": "Alle akzeptieren", - "cookieConsent.essentialOnly": "Nur Essenzielle", - "cookieConsent.learnMore": "Mehr erfahren", - "landing.nav.why": "Warum wir?", - "landing.nav.formats": "Formate", - "landing.nav.pricing": "Preise", - "landing.nav.login": "Anmelden", - "landing.nav.startFree": "Kostenlos starten", - "landing.hero.tag": "Professionelle Dokument-KI", - "landing.hero.titleLine1": "Übersetzen Sie Ihre Dokumente.", - "landing.hero.titleLine2": "Mit perfekter Formatierung.", - "landing.hero.description": "Der einzige Übersetzer, der SmartArt, Diagramme, Inhaltsverzeichnisse, Formen und komplexe Layouts bewahrt — genau wie im Original.", - "landing.hero.ctaMain": "Kostenlos starten — 2 Docs/Monat", - "landing.hero.ctaSec": "Angebote sehen", - "landing.hero.deleted": "Dateien nach 60 Min. gelöscht", - "landing.hero.noHidden": "Keine versteckten Gebühren", - "landing.hero.preview": "Vorschau vor Bezahlung", - "landing.hero.formattedOk": "Formatierung OK", - "landing.hero.aiActive": "KI-Übersetzung aktiv", - "landing.steps.title": "Wie funktioniert es?", - "landing.steps.subtitle": "Drei Schritte. Kein Formatverlust.", - "landing.steps.step1.num": "01", - "landing.steps.step1.title": "Datei hochladen", - "landing.steps.step1.desc": "Drag & Drop Ihres Excel-, Word-, PowerPoint- oder PDF-Dokuments.", - "landing.steps.step2.num": "02", - "landing.steps.step2.title": "Sprache & Engine wählen", - "landing.steps.step2.desc": "Zielsprache und Engine auswählen — klassisch oder kontextbewusste KI.", - "landing.steps.step3.num": "03", - "landing.steps.step3.title": "Ergebnis herunterladen", - "landing.steps.step3.desc": "Erhalten Sie Ihr übersetztes Dokument mit identischer Formatierung wie das Original.", - "landing.features.tag": "KI-Übersetzungsengine", - "landing.features.title": "Übersetzung, die Ihr Handwerk versteht", - "landing.features.description": "Unsere KI-Modelle analysieren den Kontext, respektieren Ihre Terminologie und übersetzen sogar Text in Bildern.", - "landing.features.context.title": "Branchenkontext", - "landing.features.context.desc": "Beschreiben Sie Ihr Fachgebiet und erhalten Sie maßgeschneiderte Übersetzungen — nicht generische.", - "landing.features.glossary.title": "Fachglossare", - "landing.features.glossary.desc": "Definieren Sie Ihre Fachbegriffe. CTA bleibt «Luftbehandlungsanlage», nie «Call To Action».", - "landing.features.vision.title": "Bilderkennung", - "landing.features.vision.desc": "Text in Bildern, Diagrammen und Grafiken wird erkannt und übersetzt.", - "landing.features.demo.source": "Quelle (FR)", - "landing.features.demo.google": "Google Translate", - "landing.features.demo.ours": "Unsere KI", - "landing.layout.title": "Ihre Formatierung,", - "landing.layout.title2": "perfekt erhalten", - "landing.layout.subtitle": "Andere Übersetzer zerstören Ihr Layout. Wir nicht.", - "landing.layout.p1.title": "SmartArt & Diagramme", - "landing.layout.p1.desc": "Organigramme, Flussdiagramme, Hierarchien — alles identisch übersetzt.", - "landing.layout.p2.title": "Inhaltsverzeichnisse", - "landing.layout.p2.desc": "Inhaltsverzeichniseinträge, Seitenzahlen und Querverweise korrekt aktualisiert.", - "landing.layout.p3.title": "Diagramme & Grafiken", - "landing.layout.p3.desc": "Titel, Achsenbeschriftungen, Legenden und Reihennamen — alles übersetzt.", - "landing.layout.p4.title": "Formen & Textfelder", - "landing.layout.p4.desc": "Rechtecke, abgerundete Blöcke, Legenden — überall lokalisiert.", - "landing.layout.p5.title": "Kopf- & Fußzeilen", - "landing.layout.p5.desc": "Kopfzeilen, Fußzeilen und Fußnoten werden nie übersehen.", - "landing.layout.p6.title": "130+ Sprachen", - "landing.layout.p6.desc": "Google Translate, DeepL und professionelle KI-Engines.", - "landing.formats.title": "Jedes Format,", - "landing.formats.title2": "jedes Element", - "landing.formats.subtitle": "Wir übersetzen, was andere vergessen. Ihr Unternehmen verdient einwandfreie Dokumentation.", - "landing.formats.word.name": "Word", - "landing.formats.word.i1": "Absätze und Überschriften", - "landing.formats.word.i2": "Tabellen und Diagramme", - "landing.formats.word.i3": "SmartArt-Diagramme", - "landing.formats.word.i4": "Inhaltsverzeichnis", - "landing.formats.word.i5": "Kopf- und Fußzeilen", - "landing.formats.word.i6": "Formen und Textfelder", - "landing.formats.word.i7": "Fuß- und Endnoten", - "landing.formats.excel.name": "Excel", - "landing.formats.excel.i1": "Zellwerte", - "landing.formats.excel.i2": "Blattnamen", - "landing.formats.excel.i3": "Diagramme und Beschriftungen", - "landing.formats.excel.i4": "Kopf- und Fußzeilen", - "landing.formats.excel.i5": "Verbundene Zellen erhalten", - "landing.formats.pptx.name": "PowerPoint", - "landing.formats.pptx.i1": "Folientext und Notizen", - "landing.formats.pptx.i2": "Diagramme und Grafiken", - "landing.formats.pptx.i3": "Formen und Textfelder", - "landing.formats.pptx.i4": "Folienmaster", - "landing.formats.pptx.i5": "Animationen erhalten", - "landing.formats.pdf.name": "PDF", - "landing.formats.pdf.i1": "Textbasierte PDFs", - "landing.formats.pdf.i2": "Layout erhalten", - "landing.formats.pdf.i3": "Bilder an Ort und Stelle", - "landing.formats.pdf.i4": "Tabellen beibehalten", - "landing.formats.pdf.i5": "Ausgabe als DOCX oder PDF", - "landing.pricing.title": "Einfache, ehrliche Preise", - "landing.pricing.subtitle": "Was Sie sehen, ist was Sie zahlen. Keine versteckten Gebühren.", - "landing.pricing.monthly": "Monatlich", - "landing.pricing.annual": "Jährlich", - "landing.pricing.bestValue": "Am beliebtesten", - "landing.pricing.month": "/Monat", - "landing.pricing.footer": "Der angezeigte Preis ist der Preis, den Sie zahlen. Keine versteckten Gebühren nach der Übersetzung.", - "landing.pricing.starter.name": "Starter", - "landing.pricing.starter.desc": "Für Einzelpersonen und kleine Projekte", - "landing.pricing.starter.f1": "50 Dokumente / Monat", - "landing.pricing.starter.f2": "Bis zu 50 Seiten pro Dokument", - "landing.pricing.starter.f3": "Google Translate + DeepL", - "landing.pricing.starter.f4": "Dateien bis zu 10 MB", - "landing.pricing.starter.cta": "Loslegen", - "landing.pricing.pro.name": "Pro", - "landing.pricing.pro.desc": "Für anspruchsvolle Profis", - "landing.pricing.pro.f1": "200 Dokumente / Monat", - "landing.pricing.pro.f2": "Bis zu 200 Seiten pro Dokument", - "landing.pricing.pro.f3": "KI-gestützte Übersetzung", - "landing.pricing.pro.f4": "Google + DeepL inklusive", - "landing.pricing.pro.f5": "Individuelle Glossare & Prompts", - "landing.pricing.pro.f6": "Prioritäts-Support", - "landing.pricing.pro.cta": "Pro testen", - "landing.pricing.business.name": "Business", - "landing.pricing.business.desc": "Für Teams mit hohem Bedarf", - "landing.pricing.business.f1": "1 000 Dokumente / Monat", - "landing.pricing.business.f2": "Bis zu 500 Seiten pro Dokument", - "landing.pricing.business.f3": "Premium-KI (Claude)", - "landing.pricing.business.f4": "Alle Anbieter + API-Zugang", - "landing.pricing.business.f5": "Webhooks & Automatisierung", - "landing.pricing.business.f6": "5 Teamplätze", - "landing.pricing.business.cta": "Kontaktieren Sie uns", - "landing.cta.title": "In 30 Sekunden mit der Übersetzung beginnen", - "landing.cta.subtitle": "Keine Kreditkarte erforderlich. Probieren Sie es jetzt kostenlos und erwecken Sie Ihre mehrsprachigen Dokumente zum Leben.", - "landing.cta.button": "Kostenloses Konto erstellen", - "landing.cta.secure": "Geschützt durch AES-256-Verschlüsselung", - "landing.footer.desc": "Experte für intelligente Dokumentenübersetzung. Wir verbinden die Kunst des Layouts mit der Wissenschaft kontextbezogener KI.", - "landing.footer.product": "Produkt", - "landing.footer.resources": "Ressourcen", - "landing.footer.legal": "Rechtliches", - "landing.footer.rights": "© 2026 Wordly.art — Alle Rechte vorbehalten.", - "dashboard.translate.pageTitle": "Dokument übersetzen", - "dashboard.translate.pageSubtitle": "Datei importieren und Zielsprache wählen", - "dashboard.translate.errorNotificationTitle": "Fehler", - "dashboard.translate.dropzone.uploadAria": "Datei-Ablagebereich", - "dashboard.translate.dropzone.title": "Datei hierher ziehen und ablegen", - "dashboard.translate.dropzone.subtitle": "oder klicken, um auszuwählen (DOCX, XLSX, PPTX, PDF)", - "dashboard.translate.dropzone.replaceFile": "Datei ersetzen", - "dashboard.translate.language.source": "Ausgangssprache", - "dashboard.translate.language.target": "Zielsprache", - "dashboard.translate.language.loading": "Sprachen werden geladen…", - "dashboard.translate.language.autoDetect": "Automatisch erkennen", - "dashboard.translate.language.selectPlaceholder": "Auswählen…", - "dashboard.translate.language.loadErrorPrefix": "Fehler beim Laden der Sprachen", - "dashboard.translate.provider.loading": "Anbieter werden geladen…", - "dashboard.translate.provider.noneConfigured": "Keine Anbieter konfiguriert", - "dashboard.translate.provider.modelTitle": "Modell", - "dashboard.translate.provider.sectionTitle": "Anbieter", - "dashboard.translate.provider.llmDivider": "KI · Kontextbasiert", - "dashboard.translate.provider.llmDividerPro": "KI · Kontextbasiert (Pro)", - "dashboard.translate.provider.upgrade": "Auf Pro upgraden", - "dashboard.translate.provider.upgradeSuffix": "um KI-Übersetzung freizuschalten", - "dashboard.translate.trust.zeroRetention": "Keine Datenspeicherung", - "dashboard.translate.trust.deletedAfter": "Dateien nach Verarbeitung gelöscht", - "dashboard.translate.actions.uploading": "Wird hochgeladen…", - "dashboard.translate.actions.translate": "Übersetzen", - "dashboard.translate.actions.filePrefix": "Datei: ", - "dashboard.translate.actions.cancel": "Abbrechen", - "dashboard.translate.actions.tryAgain": "Erneut versuchen", - "dashboard.translate.steps.uploading": "Datei wird hochgeladen…", - "dashboard.translate.steps.starting": "Übersetzung wird gestartet…", - "dashboard.translate.complete.title": "Übersetzung abgeschlossen!", - "dashboard.translate.complete.descNamed": "Ihre Datei {name} wurde erfolgreich übersetzt.", - "dashboard.translate.complete.descGeneric": "Ihre Datei wurde erfolgreich übersetzt.", - "dashboard.translate.complete.downloading": "Wird heruntergeladen…", - "dashboard.translate.complete.download": "Herunterladen", - "dashboard.translate.complete.newTranslation": "Neue Übersetzung", - "dashboard.translate.complete.toastOkTitle": "Erfolgreich", - "dashboard.translate.complete.toastOkDesc": "{name} wurde erfolgreich heruntergeladen.", - "dashboard.translate.complete.toastFailTitle": "Fehlgeschlagen", - "dashboard.translate.complete.toastFailDesc": "Übersetzung fehlgeschlagen. Bitte versuchen Sie es erneut.", - "dashboard.translate.sourceDocument": "Quelldokument", - "dashboard.translate.configuration": "Konfiguration", - "dashboard.translate.translating": "Übersetzung läuft", - "dashboard.translate.liveMonitor": "Live-Monitor", - "dashboard.translate.summary": "Zusammenfassung", - "dashboard.translate.engine": "Engine", - "dashboard.translate.confidence": "Konfidenz", - "dashboard.translate.cancel": "Abbrechen", - "dashboard.translate.segments": "Segmente", - "dashboard.translate.characters": "Zeichen", - "dashboard.translate.elapsed": "Verstrichen", - "dashboard.translate.segPerMin": "Seg/Min", - "dashboard.translate.highQuality": "Hohe Qualität", - "dashboard.translate.quality": "Qualität", - "dashboard.translate.completed": "Übersetzung abgeschlossen", - "dashboard.translate.replace": "Ersetzen", - "dashboard.translate.pdfMode.title": "PDF-Übersetzungsmodus", - "dashboard.translate.pdfMode.preserveLayout": "Layout beibehalten", - "dashboard.translate.pdfMode.textOnly": "Nur Text", - "dashboard.translate.pdfMode.preserveLayoutDesc": "Behält Bilder, Tabellen und Formatierung. Ideal für einfache PDFs.", - "dashboard.translate.pdfMode.textOnlyDesc": "Übersetzt den gesamten Text perfekt. Saubere Ausgabe ohne Layoutprobleme.", - "dashboard.translate.pipeline.upload": "Hochladen", - "dashboard.translate.pipeline.analyze": "Analysieren", - "dashboard.translate.pipeline.translate": "Übersetzung", - "dashboard.translate.pipeline.rebuild": "Rekonstruieren", - "dashboard.translate.pipeline.finalize": "Finalisieren", - "dashboard.translate.progress.processingFallback": "Verarbeitung läuft…", - "dashboard.translate.progress.connectionLost": "Verbindung verloren. Erneut versuchen…", - "dashboard.translate.progress.failedTitle": "Übersetzung fehlgeschlagen", - "dashboard.translate.error.unexpected": "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es erneut.", - "dashboard.translate.error.noResult": "Die Übersetzung hat keine Ergebnisse geliefert. Stellen Sie sicher, dass das Dokument Text enthält, und versuchen Sie es erneut oder wählen Sie eine andere Engine.", - "dashboard.translate.error.apiKey": "Ungültiger oder fehlender API-Schlüssel. Kontaktieren Sie den Administrator zur Konfiguration.", - "dashboard.translate.error.quota": "Nutzungslimit erreicht. Versuchen Sie es in wenigen Minuten erneut oder wählen Sie eine andere Engine.", - "dashboard.translate.error.timeout": "Verbindung zum Übersetzungsdienst zeitüberschritten. Prüfen Sie Ihr Netzwerk und versuchen Sie es erneut.", - "dashboard.translate.error.sessionExpired": "Sitzung abgelaufen. Klicken Sie auf Erneut versuchen, um die Übersetzung neu zu starten.", - "dashboard.translate.error.empty": "Das Dokument scheint leer zu sein oder enthält keinen übersetzbaren Text (eingescanntes PDF?).", - "dashboard.translate.error.unsupported": "Nicht unterstütztes Dateiformat oder beschädigte Datei.", - "dashboard.translate.error.connection": "Verbindung verloren. Prüfen Sie Ihr Netzwerk und versuchen Sie es erneut.", - "dashboard.translate.error.generic": "Übersetzung fehlgeschlagen: {detail}", - "dashboard.translate.error.title": "Übersetzung fehlgeschlagen", - "dashboard.translate.retry": "Übersetzung erneut versuchen", - "dashboard.translate.newFile": "Neue Datei", - "dashboard.translate.modeAI": "KI-Modus", - "dashboard.translate.modeClassic": "Klassischer Modus", - "dashboard.translate.glossaryLLMHint": "Glossare im KI-Modus verfügbar", - "dashboard.translate.submitting": "Wird gesendet...", - "dashboard.translate.submit": "Übersetzung starten", - "dashboard.translate.noFile": "Laden Sie zuerst eine Datei hoch", - "dashboard.translate.noTargetLang": "Wählen Sie eine Zielsprache", - "glossaries.yourGlossaries": "Ihre Glossare", - "glossaries.title": "Glossare & Kontext", - "glossaries.description": "Verwalten Sie Ihre Glossare und Kontextanweisungen für genauere Übersetzungen.", - "glossaries.createNew": "Neu erstellen", - "glossaries.empty": "Noch keine Glossare", - "glossaries.emptyDesc": "Erstellen Sie Ihr erstes Glossar oder laden Sie eine professionelle Vorlage oben", - "glossaries.defineTerms": "Begriffe", - "glossaries.aboutTitle": "Über Glossare", - "glossaries.aboutDesc": "Glossare ermöglichen es Ihnen, exakte Übersetzungen für bestimmte Begriffe zu definieren. Bei der Übersetzung werden die Glossarbegriffe für konsistente und präzise Übersetzungen verwendet.", - "glossaries.aboutFormat": "Jeder Begriff hat ein Quellwort und Übersetzungen in mehreren Sprachen. Wählen Sie ein Glossar auf der Übersetzungsseite aus, um es anzuwenden.", - "glossaries.toast.created": "Glossar erstellt", - "glossaries.toast.createdDesc": "Das Glossar \"{name}\" wurde erstellt.", - "glossaries.toast.imported": "Glossar importiert", - "glossaries.toast.importedDesc": "Das Glossar \"{name}\" wurde importiert.", - "glossaries.toast.updated": "Glossar aktualisiert", - "glossaries.toast.updatedDesc": "Das Glossar \"{name}\" wurde aktualisiert.", - "glossaries.toast.deleted": "Glossar gelöscht", - "glossaries.toast.deletedDesc": "Das Glossar wurde gelöscht.", - "glossaries.toast.error": "Fehler", - "glossaries.toast.errorCreate": "Glossar konnte nicht erstellt werden", - "glossaries.toast.errorImport": "Glossar konnte nicht importiert werden", - "glossaries.toast.errorUpdate": "Glossar konnte nicht aktualisiert werden", - "glossaries.toast.errorDelete": "Glossar konnte nicht gelöscht werden", - "glossaries.dialog.title": "Neues Glossar", - "glossaries.dialog.description": "Erstellen Sie ein Glossar für Ihre Übersetzungen", - "glossaries.dialog.nameLabel": "Name", - "glossaries.dialog.namePlaceholder": "Mein Glossar", - "glossaries.dialog.tabTemplates": "Vorlagen", - "glossaries.dialog.tabFile": "Datei", - "glossaries.dialog.tabManual": "Manuell", - "glossaries.dialog.cancel": "Abbrechen", - "glossaries.dialog.creating": "Wird erstellt…", - "glossaries.dialog.importing": "Wird importiert…", - "glossaries.dialog.importBtn": "Importieren", - "glossaries.dialog.selectPrompt": "Auswählen", - "glossaries.dialog.createBtn": "Erstellen", - "glossaries.dialog.createEmpty": "Leer erstellen", - "glossaries.dialog.terms": "Begriffe", - "glossaries.dialog.templatesDesc": "Wählen Sie eine vordefinierte Vorlage", - "glossaries.dialog.templatesEmpty": "Keine Vorlagen verfügbar", - "glossaries.dialog.dropTitle": "CSV-Datei hierher ziehen", - "glossaries.dialog.dropOr": "oder", - "glossaries.dialog.dropFormats": "CSV, TSV, TXT", - "glossaries.termEditor.addTerm": "Begriff hinzufügen", - "glossaries.termEditor.maxReached": "Maximal {max} Begriffe pro Glossar erreicht.", - "glossaries.dialog.formatTitle": "Format", - "glossaries.dialog.formatDesc": "Quelle,Ziel (eine pro Zeile)", - "glossaries.dialog.formatNote": "Erste Zeile wird bei erkanntem Header übersprungen", - "glossaries.dialog.errorFormat": "Nicht unterstütztes Format", - "glossaries.dialog.errorSize": "Datei zu groß", - "glossaries.dialog.errorEmpty": "Leere Datei", - "glossaries.dialog.errorRead": "Lesefehler", - "glossaries.dialog.parsing": "Wird analysiert…", - "glossaries.dialog.termsImported": "Begriffe importiert", - "glossaries.dialog.changeFile": "Datei ändern", - "glossaries.dialog.retry": "Erneut versuchen", - "glossaries.edit.title": "Modifier le glossaire", - "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", - "glossaries.edit.nameLabel": "Nom du glossaire", - "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", - "glossaries.edit.sourceLang": "Langue source", - "glossaries.edit.targetLang": "Langue cible", - "glossaries.edit.termsLabel": "Termes ({count} valides)", - "glossaries.edit.exportCsv": "Exporter CSV", - "glossaries.edit.importCsv": "Importer CSV", - "glossaries.edit.cancel": "Annuler", - "glossaries.edit.saving": "Enregistrement...", - "glossaries.edit.saveChanges": "Enregistrer les modifications", - "glossaries.edit.importFailedTitle": "Échec de l'importation", - "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", - "glossaries.edit.importSuccessTitle": "Importation réussie", - "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", - "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", - "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", - "glossaries.delete.title": "Supprimer le glossaire", - "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", - "glossaries.delete.warning": "Cette action est irréversible", - "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", - "glossaries.delete.cancel": "Annuler", - "glossaries.delete.deleting": "Suppression...", - "glossaries.delete.deleteBtn": "Supprimer", - "glossaries.upgrade.title": "Glossaires", - "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", - "glossaries.upgrade.feature1": "Créez plusieurs glossaires", - "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", - "glossaries.upgrade.feature3": "Importez/exportez via CSV", - "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", - "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", - "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", - "glossaries.upgrade.proLabel": "Pro", - "glossaries.upgrade.upgradeBtn": "Passer à Pro", - "glossaries.loading": "Chargement...", - "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", - "glossaries.howItWorks.step1Title": "Configurez ici", - "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", - "glossaries.howItWorks.step2Title": "Activez dans Traduire", - "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", - "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", - "glossaries.howItWorks.goToTranslate": "Aller à Traduire", - "glossaries.status.unsaved": "Non enregistré", - "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", - "glossaries.status.inactive": "Inactif", - "glossaries.instructions.whatForBold": "À quoi ça sert ?", - "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", - "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", - "glossaries.instructions.charCount": "{count} caractères", - "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", - "glossaries.instructions.clearAll": "Tout effacer", - "glossaries.instructions.saving": "Enregistrement…", - "glossaries.instructions.saved": "Enregistré", - "glossaries.presets.whatForBold": "À quoi ça sert ?", - "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", - "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", - "glossaries.presets.creating": "Création…", - "glossaries.presets.alreadyImported": "Déjà importé", - "glossaries.presets.it.title": "IT / Logiciel", - "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", - "glossaries.presets.legal.title": "Juridique / Contrats", - "glossaries.presets.legal.desc": "Droit des affaires, contentieux", - "glossaries.presets.medical.title": "Médical / Santé", - "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", - "glossaries.presets.finance.title": "Finance / Comptabilité", - "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", - "glossaries.presets.marketing.title": "Marketing / Publicité", - "glossaries.presets.marketing.desc": "Digital, branding, analytics", - "glossaries.presets.hr.title": "RH / Ressources Humaines", - "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", - "glossaries.presets.scientific.title": "Scientifique / Recherche", - "glossaries.presets.scientific.desc": "Publications, thèses, articles", - "glossaries.presets.ecommerce.title": "E-commerce / Vente", - "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", - "glossaries.grid.title": "Vos", - "glossaries.grid.titleHighlight": "glossaires", - "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", - "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", - "glossaries.grid.activeTranslation": "Traduction active :", - "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", - "glossaries.badge.compatible": "Compatible", - "glossaries.badge.otherTarget": "Autre cible", - "glossaries.card.editTerms": "Modifier les termes", - "glossaries.card.created": "Erstellt", - "glossaries.card.term": "Begriff", - "glossaries.card.delete": "Supprimer", - "glossaries.grid.searchPlaceholder": "Search a glossary…", - "glossaries.grid.noResults": "No results for this search.", - "glossaries.detail.backToList": "Back to glossaries", - "glossaries.detail.save": "Save", - "glossaries.detail.savedTitle": "Saved", - "glossaries.detail.savedDesc": "The glossary has been updated.", - "glossaries.detail.settingsTitle": "Settings", - "glossaries.detail.sourceLang": "Source language", - "glossaries.detail.targetLang": "Target language", - "glossaries.detail.termsTitle": "Terms", - "glossaries.detail.terms": "terms", - "glossaries.detail.searchTerms": "Filter…", - "glossaries.detail.noTerms": "No terms yet.", - "glossaries.detail.addFirstTerm": "Add the first term", - "glossaries.detail.addTerm": "Add a term", - "glossaries.detail.maxReached": "Maximum limit reached", - "glossaries.detail.source": "Source", - "glossaries.detail.target": "Target", - "glossaries.detail.sourcePlaceholder": "source term", - "glossaries.detail.targetPlaceholder": "target term", - "glossaries.detail.csvTitle": "CSV", - "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", - "glossaries.detail.export": "Export", - "glossaries.detail.import": "Import", - "glossaries.detail.dangerTitle": "Danger zone", - "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", - "glossaries.detail.deleteGlossary": "Delete this glossary", - "glossaries.detail.confirmDelete": "Confirm deletion?", - "glossaries.detail.confirm": "Confirm", - "glossaries.detail.cancel": "Cancel", - "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", - "glossaries.detail.sourceLocked": "fixed", - "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", - "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", - "glossaries.detail.notFoundTitle": "Glossary not found", - "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", - "glossaries.detail.maxTermsTitle": "Limit reached", - "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", - "glossaries.detail.importEmptyTitle": "Empty file", - "glossaries.detail.importEmptyDesc": "No terms detected in this file.", - "glossaries.detail.importedTitle": "Imported", - "glossaries.detail.importedDesc": "{count} terms imported.", - "glossaries.detail.importErrorTitle": "Read error", - "glossaries.detail.importErrorDesc": "Unable to read the file.", - "apiKeys.webhook.title": "Intégration Webhook", - "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", - "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", - "apiKeys.webhook.codeParam": "webhook_url", - "translate.mode.label": "Mode de traduction", - "translate.mode.classic": "Classique", - "translate.mode.classicDesc": "Rapide", - "translate.mode.proLlm": "Pro LLM", - "translate.mode.proLlmDesc": "Contextuel", - "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", - "translate.mode.upgradeLink": "Passer à Pro", - "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", - "pricing.nav.back": "Zurück", - "pricing.nav.home": "Startseite", - "pricing.nav.mySubscription": "Mein Abonnement", - "pricing.header.badge": "KI-Modelle aktualisiert — März 2026", - "pricing.header.title": "Der passende Plan für jedes Bedürfnis", - "pricing.header.subtitle": "Übersetzen Sie Ihre Word-, Excel- und PowerPoint-Dokumente unter Beibehaltung des Original-Layouts. Ohne API-Schlüssel.", - "pricing.billing.monthly": "Monatlich", - "pricing.billing.yearly": "Jährlich", - "pricing.plans.free.name": "Kostenlos", - "pricing.plans.starter.name": "Starter", - "pricing.plans.pro.name": "Pro", - "pricing.plans.business.name": "Business", - "pricing.plans.enterprise.name": "Enterprise", - "pricing.plans.free.description": "Perfekt zum Kennenlernen der App", - "pricing.plans.starter.description": "Für Einzelpersonen und kleine Projekte", - "pricing.plans.pro.description": "Für Professionals und wachsende Teams", - "pricing.plans.business.description": "Für Teams und Organisationen", - "pricing.plans.enterprise.description": "Maßgeschneiderte Lösungen für große Organisationen", - "pricing.plans.pro.highlight": "Am beliebtesten", - "pricing.plans.pro.badge": "BELIEBT", - "pricing.plans.enterprise.badge": "AUF ANFRAGE", - "pricing.plans.free.feat1": "5 Dokumente / Monat", - "pricing.plans.free.feat2": "Bis zu 15 Seiten pro Dokument", - "pricing.plans.free.feat3": "Google Übersetzer inklusive", - "pricing.plans.free.feat4": "Alle Sprachen (130+)", - "pricing.plans.free.feat5": "Community-Support", - "pricing.plans.starter.feat1": "50 Dokumente / Monat", - "pricing.plans.starter.feat2": "Bis zu 50 Seiten pro Dokument", - "pricing.plans.starter.feat3": "Google Übersetzer + DeepL", - "pricing.plans.starter.feat4": "Dateien bis zu 10 MB", - "pricing.plans.starter.feat5": "E-Mail-Support", - "pricing.plans.starter.feat6": "30 Tage Verlauf", - "pricing.plans.pro.feat1": "200 Dokumente / Monat", - "pricing.plans.pro.feat2": "Bis zu 200 Seiten pro Dokument", - "pricing.plans.pro.feat3": "KI-Basisübersetzung", - "pricing.plans.pro.feat4": "Google Übersetzer + DeepL", - "pricing.plans.pro.feat5": "Dateien bis zu 25 MB", - "pricing.plans.pro.feat6": "Benutzerdefinierte Glossare", - "pricing.plans.pro.feat7": "Prioritäts-Support", - "pricing.plans.pro.feat8": "90 Tage Verlauf", - "pricing.plans.business.feat1": "1.000 Dokumente / Monat", - "pricing.plans.business.feat2": "Bis zu 500 Seiten pro Dokument", - "pricing.plans.business.feat3": "Basis- + Premium-KI (Claude Haiku)", - "pricing.plans.business.feat4": "Alle Übersetzungsanbieter", - "pricing.plans.business.feat5": "Dateien bis zu 50 MB", - "pricing.plans.business.feat6": "API-Zugang (10.000 Aufrufe/Monat)", - "pricing.plans.business.feat7": "Benachrichtigungs-Webhooks", - "pricing.plans.business.feat8": "Dedizierter Support", - "pricing.plans.business.feat9": "1 Jahr Verlauf", - "pricing.plans.business.feat10": "Erweiterte Analysen", - "pricing.plans.enterprise.feat1": "Unbegrenzte Dokumente", - "pricing.plans.enterprise.feat2": "Alle KI-Modelle (GPT-5, Claude Opus 4.6…)", - "pricing.plans.enterprise.feat3": "On-Premise oder dedizierte Cloud", - "pricing.plans.enterprise.feat4": "99,9 % SLA garantiert", - "pricing.plans.enterprise.feat5": "24/7 dedizierter Support", - "pricing.plans.enterprise.feat6": "White-Label", - "pricing.plans.enterprise.feat7": "Unbegrenzte Teams", - "pricing.plans.enterprise.feat8": "Maßgeschneiderte Integrationen", - "pricing.card.onRequest": "Auf Anfrage", - "pricing.card.free": "Kostenlos", - "pricing.card.perMonth": "/Monat", - "pricing.card.billedYearly": "{price} € / Jahr abgerechnet", - "pricing.card.documents": "Dokumente", - "pricing.card.pagesMax": "Max. Seiten", - "pricing.card.aiTranslation": "KI-Übersetzung", - "pricing.card.unlimited": "Unbegrenzt", - "pricing.card.perMonthStat": "/ Monat", - "pricing.card.perDoc": "S. / Dok.", - "pricing.card.aiEssential": "Basis", - "pricing.card.aiEssentialPremium": "Basis + Premium", - "pricing.card.aiCustom": "Maßgeschneidert", - "pricing.card.myPlan": "Mein Plan", - "pricing.card.managePlan": "Plan verwalten", - "pricing.card.startFree": "Kostenlos starten", - "pricing.card.contactUs": "Kontaktieren Sie uns", - "pricing.card.choosePlan": "Diesen Plan wählen", - "pricing.card.processing": "Wird verarbeitet…", - "pricing.comparison.title": "Detaillierter Vergleich", - "pricing.comparison.subtitle": "Alles, was in jedem Plan enthalten ist", - "pricing.comparison.feature": "Funktion", - "pricing.comparison.docsPerMonth": "Dokumente / Monat", - "pricing.comparison.pagesMaxPerDoc": "Max. Seiten / Dokument", - "pricing.comparison.maxFileSize": "Max. Dateigröße", - "pricing.comparison.googleTranslation": "Google Übersetzer", - "pricing.comparison.deepl": "DeepL", - "pricing.comparison.aiEssential": "KI-Basisübersetzung", - "pricing.comparison.aiPremium": "KI-Premiumübersetzung", - "pricing.comparison.apiAccess": "API-Zugang", - "pricing.comparison.priorityProcessing": "Prioritätsverarbeitung", - "pricing.comparison.support": "Support", - "pricing.comparison.support.community": "Community", - "pricing.comparison.support.email": "E-Mail", - "pricing.comparison.support.priority": "Priorität", - "pricing.comparison.support.dedicated": "Dediziert", - "pricing.comparison.mb": "MB", - "pricing.credits.title": "Zusätzliche Guthaben", - "pricing.credits.subtitle": "Mehr benötigt? Guthaben einzeln kaufen, ohne Abo.", - "pricing.credits.perPage": "1 Guthaben = 1 übersetzte Seite.", - "pricing.credits.bestValue": "Bestes Preis-Leistungs-Verhältnis", - "pricing.credits.unit": "Guthaben", - "pricing.credits.centsPerCredit": "ct / Guthaben", - "pricing.credits.buy": "Kaufen", - "pricing.trust.encryption.title": "Ende-zu-Ende-Verschlüsselung", - "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 im Ruhezustand", - "pricing.trust.languages.title": "130+ Sprachen", - "pricing.trust.languages.sub": "Einschließlich Arabisch, Persisch, Hebräisch (RTL)", - "pricing.trust.parallel.title": "Parallele Verarbeitung", - "pricing.trust.parallel.sub": "Ultraschnelle Multi-Thread-KI", - "pricing.trust.availability.title": "24/7 verfügbar", - "pricing.trust.availability.sub": "99,9 % garantierte Verfügbarkeit", - "pricing.aiModels.title": "Unsere KI-Modelle — März 2026", - "pricing.aiModels.essential.title": "KI-Basisübersetzung", - "pricing.aiModels.essential.plan": "Pro-Plan", - "pricing.aiModels.essential.descPrefix": "Basierend auf", - "pricing.aiModels.essential.descSuffix": "— dem kosteneffizientesten KI-Modell 2026. Qualität vergleichbar mit Frontier-Modellen zu einem Bruchteil der Kosten.", - "pricing.aiModels.essential.modelName": "unser Essentielles KI-Modell", - "pricing.aiModels.essential.context": "163K Token Kontext", - "pricing.aiModels.essential.value": "Hervorragendes Preis-Leistungs-Verhältnis", - "pricing.aiModels.premium.title": "KI-Premiumübersetzung", - "pricing.aiModels.premium.plan": "Business-Plan", - "pricing.aiModels.premium.descPrefix": "Basierend auf", - "pricing.aiModels.premium.descSuffix": "von Anthropic — präzise bei juristischen, medizinischen und komplexen technischen Dokumenten.", - "pricing.aiModels.premium.context": "200K Token Kontext", - "pricing.aiModels.premium.precision": "Höchste Genauigkeit", - "pricing.faq.title": "Häufig gestellte Fragen", - "pricing.faq.q1": "Kann ich jederzeit den Plan wechseln?", - "pricing.faq.a1": "Ja. Ein Upgrade erfolgt sofort und anteilig. Ein Downgrade wird am Ende des aktuellen Zeitraums wirksam.", - "pricing.faq.q2": "Was ist die «KI-Basisübersetzung»?", - "pricing.faq.a2": "Unser KI-Motor versteht den Kontext Ihrer Dokumente, erhält das Layout und verarbeitet Fachbegriffe deutlich besser als klassische Übersetzungen.", - "pricing.faq.q3": "Was ist der Unterschied zwischen Basis- und Premium-KI?", - "pricing.faq.a3": "Die Basis-KI nutzt ein optimiertes Modell (hervorragendes Preis-Leistungs-Verhältnis). Die Premium-KI verwendet Claude 3.5 Haiku von Anthropic und ist genauer bei juristischen, medizinischen und komplexen technischen Dokumenten.", - "pricing.faq.q4": "Werden meine Dokumente nach der Übersetzung gespeichert?", - "pricing.faq.a4": "Übersetzte Dateien sind je nach Plan verfügbar (30 Tage Starter, 90 Tage Pro, 1 Jahr Business). Sie sind im Ruhezustand und bei der Übertragung verschlüsselt.", - "pricing.faq.q5": "Was passiert, wenn ich mein monatliches Kontingent überschreite?", - "pricing.faq.a5": "Sie können einzelne Guthaben kaufen oder Ihr Abo upgraden. Sie werden bei 80 % Nutzung benachrichtigt.", - "pricing.faq.q6": "Gibt es eine kostenlose Testversion für kostenpflichtige Pläne?", - "pricing.faq.a6": "Der Kostenlos-Plan ist dauerhaft und ohne Kreditkarte. Für Pro und Business kontaktieren Sie uns für eine 14-tägige Testphase.", - "pricing.faq.q7": "Welche Dateiformate werden unterstützt?", - "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx) und bald PDF. Alle Pläne unterstützen dieselben Formate.", - "pricing.cta.title": "Bereit loszulegen?", - "pricing.cta.subtitle": "Starten Sie kostenlos, ohne Kreditkarte. Upgraden Sie, wenn Sie möchten.", - "pricing.cta.createAccount": "Kostenloses Konto erstellen", - "pricing.cta.login": "Anmelden", - "pricing.toast.demo": "Demo-Modus — Stripe ist noch nicht konfiguriert. In der Produktion würden Sie zur Zahlung weitergeleitet, um den Plan {planId} zu aktivieren.", - "pricing.toast.networkError": "Netzwerkfehler. Bitte versuchen Sie es erneut.", - "pricing.toast.paymentError": "Fehler beim Erstellen der Zahlung.", - "register.title": "Konto erstellen", - "register.subtitle": "Kostenlos mit dem Übersetzen beginnen", - "register.error.failed": "Registrierung fehlgeschlagen", - "register.name.label": "Name", - "register.name.placeholder": "Ihr Name", - "register.name.error": "Der Name muss mindestens 2 Zeichen lang sein", - "register.email.label": "E-Mail-Adresse", - "register.email.placeholder": "sie@beispiel.de", - "register.email.error": "Ungültige E-Mail-Adresse", - "register.password.label": "Passwort", - "register.password.error": "Das Passwort muss mindestens 8 Zeichen haben, mit Großbuchstabe, Kleinbuchstabe und Ziffer", - "register.password.show": "Passwort anzeigen", - "register.password.hide": "Passwort verbergen", - "register.password.strengthLabel": "Stärke:", - "register.password.strength.weak": "Schwach", - "register.password.strength.medium": "Mittel", - "register.password.strength.strong": "Stark", - "register.confirmPassword.label": "Passwort bestätigen", - "register.confirmPassword.error": "Passwörter stimmen nicht überein", - "register.confirmPassword.show": "Anzeigen", - "register.confirmPassword.hide": "Verbergen", - "register.submit.creating": "Konto wird erstellt...", - "register.submit.create": "Mein Konto erstellen", - "register.hasAccount": "Bereits ein Konto?", - "register.login": "Anmelden", - "register.terms.prefix": "Mit der Kontoerstellung akzeptieren Sie unsere", - "register.terms.link": "Nutzungsbedingungen", - "login.errorTitle": "Login Error", - "login.welcomeBack": "Welcome back", - "login.signInToContinue": "Sign in to continue translating", - "login.email": "Email", - "login.emailPlaceholder": "you@example.com", - "login.password": "Password", - "login.forgotPassword": "Forgot password?", - "login.passwordPlaceholder": "••••••••", - "login.signingIn": "Signing in...", - "login.signIn": "Sign In", - "login.noAccount": "Don't have an account?", - "login.signUpFree": "Sign up for free", - "login.orContinueWith": "oder mit E-Mail fortfahren", - "login.google.connecting": "Verbinden…", - "login.google.errorGeneric": "Bei der Google-Anmeldung ist ein Fehler aufgetreten.", - "login.google.errorFailed": "Google-Anmeldung fehlgeschlagen. Bitte erneut versuchen.", - "forgotPassword.enterEmail": "Please enter your email address", - "forgotPassword.error": "An error occurred", - "forgotPassword.title": "Forgot Password", - "forgotPassword.checkEmail": "Check your inbox", - "forgotPassword.subtitle": "Enter your email to receive a reset link", - "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", - "forgotPassword.emailLabel": "Email address", - "forgotPassword.emailPlaceholder": "you@example.com", - "forgotPassword.sending": "Sending...", - "forgotPassword.sendLink": "Send reset link", - "forgotPassword.backToLogin": "Back to login", - "forgotPassword.loading": "Loading...", - "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", - "resetPassword.passwordMismatch": "Passwords do not match", - "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", - "resetPassword.error": "An error occurred", - "resetPassword.invalidLink": "Invalid link", - "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", - "resetPassword.requestNewLink": "Request new link", - "resetPassword.successTitle": "Password reset", - "resetPassword.newPasswordTitle": "New password", - "resetPassword.successSubtitle": "You will be redirected to login", - "resetPassword.subtitle": "Set your new password", - "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", - "resetPassword.newPassword": "New password", - "resetPassword.showPassword": "Show password", - "resetPassword.hidePassword": "Hide password", - "resetPassword.confirmPassword": "Confirm password", - "resetPassword.resetting": "Resetting...", - "resetPassword.resetPassword": "Reset password", - "resetPassword.backToLogin": "Back to login", - "resetPassword.loading": "Loading...", - "common.loading": "Laden...", - "profile.header.title": "Mein Profil", - "profile.header.subtitle": "Verwalten Sie Ihr Konto und Ihre Einstellungen.", - "profile.tabs.account": "Konto", - "profile.tabs.subscription": "Abonnement", - "profile.tabs.preferences": "Einstellungen", - "profile.account.user": "Benutzer", - "profile.account.memberSince": "Mitglied seit", - "profile.plan.label": "Plan", - "profile.plan.free": "Kostenlos", - "profile.plan.starter": "Starter", - "profile.plan.pro": "Pro", - "profile.plan.business": "Business", - "profile.plan.enterprise": "Enterprise", - "profile.plan.pricePerMonth": "{price} €/Monat", - "profile.subscription.canceling": "Kündigung läuft", - "profile.subscription.active": "Aktiv", - "profile.subscription.unknown": "Unbekannt", - "profile.subscription.accessUntil": "Zugang bis", - "profile.subscription.renewalOn": "Verlängerung am", - "profile.subscription.upgradePlan": "Auf einen kostenpflichtigen Plan upgraden", - "profile.subscription.changePlan": "Plan ändern", - "profile.subscription.manageBilling": "Abrechnung verwalten", - "profile.subscription.billingUnavailable": "Abrechnungsportal nicht verfügbar.", - "profile.subscription.billingError": "Fehler beim Zugriff auf das Abrechnungsportal.", - "profile.subscription.cancelSuccess": "Abonnement gekündigt. Sie behalten den Zugang bis zum Ende des Zeitraums.", - "profile.subscription.cancelError": "Fehler bei der Kündigung.", - "profile.subscription.networkError": "Netzwerkfehler.", - "profile.usage.title": "Nutzung diesen Monat", - "profile.usage.resetOn": "Zurücksetzung am", - "profile.usage.documents": "Dokumente", - "profile.usage.pages": "Seiten", - "profile.usage.extraCredits": "zusätzliches Guthaben", - "profile.usage.extraCreditsPlural": "zusätzliches Guthaben", - "profile.usage.quotaReached": "Kontingent erreicht", - "profile.usage.quotaReachedDesc": "Upgraden Sie auf einen höheren Plan, um fortzufahren.", - "profile.usage.unlockMore": "Schalten Sie mit einem kostenpflichtigen Plan mehr Übersetzungen frei.", - "profile.usage.viewPlans": "Pläne ansehen", - "profile.usage.includedInPlan": "In Ihrem Plan enthalten", - "profile.danger.title": "Gefahrenzone", - "profile.danger.description": "Die Kündigung wird am Ende Ihres aktuellen Zeitraums wirksam. Sie behalten den Zugang bis zu diesem Datum.", - "profile.danger.confirm": "Sind Sie sicher? Diese Aktion kann nicht rückgängig gemacht werden.", - "profile.danger.confirmCancel": "Kündigung bestätigen", - "profile.danger.cancelSubscription": "Mein Abonnement kündigen", - "profile.danger.keep": "Nein, behalten", - "profile.prefs.interfaceLang": "Sprache der Benutzeroberfläche", - "profile.prefs.interfaceLangDesc": "Die Sprache wird automatisch anhand Ihres Browsers erkannt. Sie können sie manuell ändern.", - "profile.prefs.defaultTargetLang": "Standard-Zielsprache", - "profile.prefs.selectLanguage": "Sprache auswählen", - "profile.prefs.defaultTargetLangDesc": "Diese Sprache wird für Ihre Übersetzungen vorausgewählt.", - "profile.prefs.save": "Speichern", - "profile.prefs.theme": "Design", - "profile.prefs.themeDesc": "Wählen Sie das Erscheinungsbild der Benutzeroberfläche", - "profile.prefs.cache": "Cache", - "profile.prefs.cacheDesc": "Das Löschen des lokalen Caches kann einige Anzeigeprobleme beheben.", - "profile.prefs.clearing": "Wird gelöscht...", - "profile.prefs.clearCache": "Cache löschen", - "settings.title": "Einstellungen", - "settings.subtitle": "Allgemeine Anwendungskonfiguration", - "settings.formats.title": "Unterstützte Formate", - "settings.formats.subtitle": "Dokumenttypen, die Sie übersetzen können", - "settings.formats.formulas": "Formeln", - "settings.formats.styles": "Stile", - "settings.formats.images": "Bilder", - "settings.formats.headers": "Kopfzeilen", - "settings.formats.tables": "Tabellen", - "settings.formats.slides": "Folien", - "settings.formats.notes": "Notizen", - "settings.cache.title": "Cache", - "settings.cache.desc": "Das Löschen des lokalen Caches kann einige Anzeigeprobleme beheben.", - "settings.cache.clearing": "Wird gelöscht...", - "settings.cache.clear": "Cache löschen", - "services.title": "Übersetzungsanbieter", - "services.subtitle": "Anbieter werden vom Administrator konfiguriert. Sie können sehen, welche derzeit für Ihr Konto verfügbar sind.", - "services.loading": "Anbieter werden geladen...", - "services.noProviders": "Derzeit sind keine Anbieter konfiguriert. Wenden Sie sich an Ihren Administrator.", - "services.classic": "Klassische Übersetzung", - "services.llmPro": "LLM · Kontextbezogen (Pro)", - "services.available": "Verfügbar", - "services.model": "Modell", - "services.adminOnly.title": "Anbieterkonfiguration ist nur für Administratoren", - "services.adminOnly.desc": "API-Schlüssel, Modellauswahl und Anbieteraktivierung werden ausschließlich vom Administrator im Admin-Panel verwaltet. Sie müssen niemals einen API-Schlüssel eingeben.", - "apiKeys.title": "API-Schlüssel", - "apiKeys.subtitle": "Verwalten Sie Ihre API-Schlüssel für den programmgesteuerten Zugriff auf die Übersetzungs-API.", - "apiKeys.loading": "Laden...", - "apiKeys.sectionTitle": "API & Automatisierung", - "apiKeys.sectionDesc": "Generieren und verwalten Sie Ihre API-Schlüssel für Automatisierungs-Workflows", - "apiKeys.keysUsed": "{total} von {max} Schlüsseln verwendet", - "apiKeys.maxReached": "Maximale Anzahl an Schlüsseln erreicht. Widerrufen Sie einen Schlüssel, um einen neuen zu generieren.", - "apiKeys.canGenerate": "Sie können {count} weiteren Schlüssel generieren", - "apiKeys.canGeneratePlural": "Sie können {count} weitere Schlüssel generieren", - "apiKeys.generateNew": "Neuen Schlüssel generieren", - "apiKeys.keyRevoked": "Schlüssel widerrufen", - "apiKeys.keyRevokedDesc": "Der API-Schlüssel wurde erfolgreich widerrufen.", - "apiKeys.keyNotFound": "Schlüssel nicht gefunden", - "apiKeys.keyNotFoundDesc": "Der API-Schlüssel existiert nicht mehr. Er wurde möglicherweise bereits widerrufen.", - "apiKeys.error": "Fehler", - "apiKeys.revokeError": "Der API-Schlüssel konnte nicht widerrufen werden. Bitte versuchen Sie es erneut.", - "apiKeys.limitReached": "Limit erreicht", - "apiKeys.limitReachedDesc": "Sie haben das Maximum von 10 API-Schlüsseln erreicht. Widerrufen Sie einen vorhandenen Schlüssel, um einen neuen zu generieren.", - "apiKeys.proRequired": "Pro-Funktion erforderlich", - "apiKeys.proRequiredDesc": "API-Schlüssel sind eine Pro-Funktion. Bitte upgraden Sie Ihr Konto.", - "apiKeys.generateError": "API-Schlüssel konnte nicht generiert werden. Bitte versuchen Sie es erneut.", - "apiKeys.upgrade.title": "API-Schlüssel", - "apiKeys.upgrade.subtitle": "Automatisieren Sie Ihre Übersetzungen mit API-Zugang", - "apiKeys.upgrade.feat1": "Generieren Sie unbegrenzt API-Schlüssel", - "apiKeys.upgrade.feat2": "Automatisieren Sie die Dokumentübersetzung", - "apiKeys.upgrade.feat3": "Webhook-Benachrichtigungen", - "apiKeys.upgrade.feat4": "LLM-Übersetzungsmodi", - "apiKeys.upgrade.proFeature": "API-Schlüssel sind eine {pro}-Funktion. Upgraden Sie, um API-Automatisierung freizuschalten.", - "apiKeys.upgrade.pro": "Pro", - "apiKeys.upgrade.cta": "Auf Pro upgraden", - "apiKeys.dialog.maxTitle": "Maximale Anzahl an Schlüsseln erreicht", - "apiKeys.dialog.maxDesc": "Sie haben das Maximum von 10 API-Schlüsseln erreicht. Bitte widerrufen Sie einen vorhandenen Schlüssel, bevor Sie einen neuen generieren.", - "apiKeys.dialog.close": "Schließen", - "apiKeys.dialog.generated": "API-Schlüssel generiert!", - "apiKeys.dialog.generatedDesc": "Ihr neuer API-Schlüssel wurde erstellt. Kopieren Sie ihn jetzt – er wird nicht erneut angezeigt.", - "apiKeys.dialog.important": "Wichtig:", - "apiKeys.dialog.importantDesc": "Dies ist das einzige Mal, dass Sie diesen Schlüssel sehen. Speichern Sie ihn sicher.", - "apiKeys.dialog.apiKey": "API-Schlüssel", - "apiKeys.dialog.name": "Name:", - "apiKeys.dialog.done": "Fertig", - "apiKeys.dialog.copied": "Ich habe den Schlüssel kopiert", - "apiKeys.dialog.generateTitle": "Neuen API-Schlüssel generieren", - "apiKeys.dialog.generateDesc": "Erstellen Sie einen neuen API-Schlüssel für den programmgesteuerten Zugriff auf die Übersetzungs-API.", - "apiKeys.dialog.keyName": "Schlüsselname (optional)", - "apiKeys.dialog.keyNamePlaceholder": "z.B., Produktion, Staging", - "apiKeys.dialog.keyNameHint": "Ein beschreibender Name, um diesen Schlüssel später zu identifizieren.", - "apiKeys.dialog.nameTooLong": "Der Name muss {max} Zeichen oder weniger haben", - "apiKeys.dialog.nameInvalid": "Der Name darf nur Buchstaben, Zahlen, Leerzeichen, Bindestriche und Unterstriche enthalten", - "apiKeys.dialog.cancel": "Abbrechen", - "apiKeys.dialog.generating": "Wird generiert...", - "apiKeys.dialog.generate": "Schlüssel generieren", - "apiKeys.table.name": "Name", - "apiKeys.table.prefix": "Präfix", - "apiKeys.table.created": "Erstellt", - "apiKeys.table.lastUsed": "Zuletzt verwendet", - "apiKeys.table.never": "Nie", - "apiKeys.table.actions": "Aktionen", - "apiKeys.table.revoke": "Widerrufen", - "apiKeys.table.copyPrefix": "Schlüsselpräfix kopieren", - "apiKeys.table.revokeKey": "Schlüssel widerrufen", - "apiKeys.revokeDialog.title": "API-Schlüssel widerrufen", - "apiKeys.revokeDialog.desc": "Sind Sie sicher, dass Sie den Schlüssel \"{name}\" widerrufen möchten? Diese Aktion kann nicht rückgängig gemacht werden.", - "apiKeys.revokeDialog.confirm": "Ja, widerrufen", - "apiKeys.revokeDialog.cancel": "Abbrechen", - "context.proTitle": "Pro-Funktion", - "context.proDesc": "Kontext und professionelle Glossare sind mit den Plänen Pro, Business und Enterprise verfügbar. Sie bieten genauere Übersetzungen durch Anweisungen und domänenspezifisches Vokabular.", - "context.viewPlans": "Pläne ansehen", - "context.title": "Kontext & Glossar", - "context.subtitle": "Verbessern Sie die Übersetzungsqualität mit Anweisungen und domänenspezifischem Vokabular.", - "context.presets.title": "Professionelle Glossare", - "context.presets.desc": "Laden Sie ein vollständiges Glossar mit Anweisungen und spezieller Terminologie", - "context.instructions.title": "Kontextanweisungen", - "context.instructions.desc": "Anweisungen, denen die KI während der Übersetzung folgt", - "context.instructions.placeholder": "Z.B.: Sie übersetzen HVAC-Fachdokumente. Verwenden Sie präzise Ingenieurterminologie...", - "context.glossary.title": "Technisches Glossar", - "context.glossary.desc": "Format: Quelle=Ziel (eines pro Zeile). Über Voreinstellung geladene Glossare sind bearbeitbar.", - "context.glossary.terms": "Begriffe im Glossar", - "context.clearAll": "Alles löschen", - "context.saving": "Wird gespeichert...", - "context.save": "Speichern", - "translate.glossary.title": "Glossar", - "translate.glossary.select": "Glossar auswählen", - "translate.glossary.none": "Keins", - "translate.glossary.terms": "Begriffe", - "translate.glossary.proOnly": "Upgraden Sie auf Pro für Glossare", - "translate.glossary.myGlossaries": "Meine Glossare", - "translate.glossary.fromTemplate": "Aus Vorlage erstellen", - "translate.glossary.noGlossaryForPair": "Kein Glossar für", - "translate.glossary.noGlossaries": "Keine Glossare", - "translate.glossary.loading": "Laden...", - "translate.glossary.classicMode": "Neutraler Motor ohne Glossar (nur KI)", - "translate.glossary.selectPlaceholder": "Glossar auswählen...", - "translate.glossary.multilingual": "MEHRSPRACHIG", - "translate.glossary.noGlossaryAvailable": "Kein Glossar verfügbar", - "translate.glossary.filterByLang": "Nach Sprache filtern", - "translate.glossary.active": "Aktiv", - "translate.glossary.inactive": "Inaktiv", - "translate.glossary.availableTemplates": "Verfügbare Vorlagen", - "translate.glossary.importing": "Importiere...", - "translate.glossary.imported": "(Importiert)", - "translate.glossary.noGlossaryForSource": "Kein Glossar oder Vorlage für Ausgangssprache", - "translate.glossary.createGlossary": "Glossar erstellen", - "translate.glossary.showAll": "Alle Glossare anzeigen", - "translate.glossary.activePreview": "Vorschau aktiver Zuordnungen:", - "translate.glossary.total": "gesamt", - "translate.glossary.moreTerms": "weitere Begriffe", - "translate.glossary.noTerms": "Keine Begriffe in diesem Glossar.", - "translate.glossary.sourceTerm": "Quellbegriff", - "translate.glossary.translation": "Übersetzung", - "translate.glossary.addTerm": "Begriff hinzufügen", - "translate.glossary.disabledMode": "Neutraler Motor ohne angewandtes Glossar", - "translate.glossary.addTermError": "Fehler beim Hinzufügen des Begriffs", - "translate.glossary.networkError": "Netzwerkfehler", - "translate.glossary.importFailed": "Import fehlgeschlagen ({status})", - "translate.glossary.helpText": "Das Glossar erzwingt die präzise Übersetzung von Begriffen. Wählen Sie ein Glossar, dessen Ausgangssprache der Originalsprache Ihres Dokuments entspricht.", - "translate.glossary.sourceWarning": "Achtung: Dieses Glossar verwendet die Ausgangssprache", - "translate.glossary.sourceWarningBut": "aber Ihr Dokument ist konfiguriert auf", - "translate.glossary.targetWarning": "Ziel-Inkompatibilität: Dieses Glossar ist für die Übersetzung in", - "translate.glossary.targetWarningBut": "aber Ihr Dokument zielt auf", - "translate.glossary.targetWarningEnd": "Die Begriffe sind möglicherweise nicht relevant.", - "context.presets.createGlossary": "Glossar erstellen", - "context.presets.created": "Glossar erstellt", - "context.presets.createdDesc": "Das Glossar \"{name}\" wurde mit {count} Begriffen erstellt.", - "context.presets.hint": "Klicken Sie auf ein Preset, um ein Glossar mit domänenspezifischen Begriffen zu erstellen. Verwalten Sie Ihre Glossare im Glossar-Bereich.", - "context.glossary.manage": "Glossare verwalten", - "context.saved": "Gespeichert", - "context.savedDesc": "Ihre Kontextanweisungen wurden gespeichert.", - "admin.login.title": "Administration", - "admin.login.required": "Anmeldung erforderlich", - "admin.login.password": "Admin-Passwort", - "admin.login.connecting": "Verbindung wird hergestellt...", - "admin.login.access": "Admin-Panel öffnen", - "admin.login.restricted": "Nur für Administratoren", - "admin.layout.checking": "Authentifizierung wird überprüft...", - "admin.dashboard.title": "Admin-Dashboard", - "admin.dashboard.subtitle": "Administratorkontrollpanel", - "admin.dashboard.refresh": "Aktualisieren", - "admin.dashboard.refreshTooltip": "Dashboard-Daten aktualisieren", - "admin.dashboard.config": "Systemkonfiguration", - "admin.dashboard.maxFileSize": "Max. Dateigröße:", - "admin.dashboard.translationService": "Übersetzungsdienst:", - "admin.dashboard.formats": "Formate:", - "admin.nav.dashboard": "Dashboard", - "admin.nav.users": "Benutzer", - "admin.nav.pricing": "Preise & Stripe", - "admin.nav.providers": "Anbieter", - "admin.nav.system": "System", - "admin.nav.logs": "Protokolle", - "admin.users.title": "Benutzerverwaltung", - "admin.users.subtitle": "Benutzerkonten anzeigen und verwalten", - "admin.users.planUpdated": "Plan aktualisiert", - "admin.users.planChanged": "Der Plan wurde erfolgreich zu \"{plan}\" geändert.", - "admin.users.unknownError": "Unbekannter Fehler", - "admin.users.error": "Fehler", - "admin.users.planUpdateError": "Plan konnte nicht aktualisiert werden: {message}", - "admin.users.noKeys": "Keine Schlüssel", - "admin.users.noKeysDesc": "Dieser Benutzer hat keine aktiven API-Schlüssel.", - "admin.users.keysRevoked": "Schlüssel widerrufen", - "admin.users.keysRevokedDesc": "{count} API-Schlüssel erfolgreich widerrufen.", - "admin.users.revokeError": "Schlüssel konnten nicht widerrufen werden: {message}", - "admin.users.retry": "Erneut versuchen", - "admin.system.title": "System", - "admin.system.subtitle": "Systemstatus überwachen und Ressourcen verwalten", - "admin.system.quotas": "Übersetzungskontingente", - "admin.system.resetQuotas": "Monatliche Kontingente zurücksetzen", - "admin.system.resetting": "Zurücksetzen...", - "admin.system.reset": "Zurücksetzen", - "admin.system.allOperational": "Alle Systeme betriebsbereit", - "admin.system.issuesDetected": "Systemprobleme erkannt", - "admin.system.waitingData": "Warte auf Daten...", - "admin.system.purging": "Bereinigung läuft...", - "admin.system.clean": "Bereinigen", - "admin.system.purge": "Bereinigen", - "memento.title": "Entdecken Sie Momento", - "memento.slogan": "Momento ist mehr als nur eine Notizen-App. Es ist ein intelligentes Ökosystem, das Ihre Ideen in Echtzeit verbindet, analysiert und weiterentwickelt – mit 6 KI-Agenten und semantischer Suche.", - "memento.ctaFree": "Kostenlos starten", - "memento.ctaMore": "Mehr erfahren", - "common.backToHome": "Zurück zur Startseite", - "dashboard.topbar.interfaceLabel": "Übersetzungsoberfläche", - "dashboard.topbar.premiumAccess": "Premium-Zugang", - "landing.hero.contextEngine": "Übersetzung erkannt: Technischer Wartungsbegriff für HVAC-Systeme...", - "landing.hero.liveAnalysis": "Live-Analyse", - "landing.hero.termsDetected": "Begriffe erkannt", - "landing.steps.process": "PROZESS", - "landing.translate.newProject": "Neues Projekt", - "landing.translate.title": "Dokument übersetzen", - "landing.translate.subtitle": "Datei importieren und Zielsprache wählen", - "landing.translate.sourceDocument": "Quelldokument", - "landing.translate.configuration": "Konfiguration", - "landing.translate.sourceLang": "Quellsprache", - "landing.translate.targetLang": "Zielsprache", - "landing.translate.provider": "Anbieter", - "landing.translate.startTranslation": "Übersetzung starten", - "landing.translate.zeroRetention": "Keine Speicherung", - "landing.translate.filesDeleted": "Dateien nach Verarbeitung gelöscht", - "landing.translate.dropHere": "Hier ablegen", - "landing.translate.supportedFormats": "DOCX, XLSX, PPTX oder PDF Dateien unterstützt", - "landing.translate.aiAnalysis": "KI-Analyse aktiv", - "landing.translate.processing": "Verarbeitung läuft", - "landing.translate.preservingLayout": "Ihr Layout wird beibehalten", - "layout.nav.apiAccess": "API-Zugang", - "layout.footer.terms": "AGB", - "layout.footer.privacy": "Datenschutz", - "fileUploader.uploadDocument": "Dokument hochladen", - "fileUploader.uploadDesc": "Datei per Drag & Drop ablegen oder klicken (Excel, Word, PowerPoint)", - "fileUploader.dropHere": "Datei hier ablegen…", - "fileUploader.dragAndDrop": "Dokument hierher ziehen", - "fileUploader.orClickBrowse": "oder klicken Sie zum Durchsuchen", - "fileUploader.preview": "Vorschau", - "fileUploader.translationOptions": "Übersetzungsoptionen", - "fileUploader.configureSettings": "Übersetzungseinstellungen anpassen", - "fileUploader.targetLanguage": "Zielsprache", - "fileUploader.selectLanguage": "Sprache wählen", - "fileUploader.translationProvider": "Übersetzungsanbieter", - "fileUploader.selectProvider": "Anbieter wählen", - "fileUploader.advancedOptions": "Erweiterte Optionen", - "fileUploader.translateImages": "Bilder übersetzen", - "fileUploader.translating": "Übersetzung läuft…", - "fileUploader.translateDocument": "Dokument übersetzen", - "fileUploader.processing": "Verarbeitung…", - "fileUploader.translationError": "Übersetzungsfehler", - "fileUploader.translationComplete": "Übersetzung abgeschlossen!", - "fileUploader.translationCompleteDesc": "Ihr Dokument wurde erfolgreich übersetzt und die Formatierung beibehalten.", - "fileUploader.download": "Übersetztes Dokument herunterladen", - "fileUploader.webgpuUnsupported": "WebGPU wird in diesem Browser nicht unterstützt. Bitte verwenden Sie Chrome 113+ oder Edge 113+.", - "fileUploader.webllmNotLoaded": "WebLLM-Modell nicht geladen. Gehen Sie zu Einstellungen > Übersetzungsdienste, um ein Modell zu laden.", - "fileUploader.extracting": "Texte aus Dokument extrahieren…", - "fileUploader.noTranslatable": "Kein übersetzbarer Text im Dokument gefunden", - "fileUploader.foundTexts": "{count} zu übersetzende Texte gefunden", - "fileUploader.translatingItem": "Übersetze {current}/{total}: „{preview}\"", - "fileUploader.reconstructing": "Dokument wird rekonstruiert…", - "fileUploader.translatingLocally": "Lokale Übersetzung mit WebLLM…", - "checkout.activating": "Wird aktiviert…", - "checkout.activatingDesc": "Wir aktualisieren Ihr Abonnement, bitte warten Sie.", - "checkout.paymentConfirmed": "Zahlung bestätigt!", - "checkout.subscriptionActivated": "Abonnement aktiviert!", - "checkout.planActivated": "{plan}-Plan aktiviert!", - "checkout.redirectingToProfile": "Weiterleitung zu Ihrem Profil…", - "checkout.paymentReceived": "Zahlung erhalten", - "checkout.redirecting": "Weiterleitung…", - "checkout.syncError": "Synchronisierungsfehler", - "checkout.networkError": "Netzwerkfehler. Ihre Zahlung ist bestätigt — bitte laden Sie Ihr Profil neu.", - "dashboard.checkoutSyncError": "Fehler beim Synchronisieren der Zahlung.", - "dashboard.networkRefresh": "Netzwerkfehler. Bitte aktualisieren Sie die Seite.", - "dashboard.continueToTranslate": "Weiter zur Übersetzung", - "langSelector.search": "Suchen…", - "langSelector.noResults": "Keine Ergebnisse", - "langSelector.source": "Quelle", - "langSelector.target": "Ziel", - "langSelector.swap": "Tauschen", - "translateComplete.highQuality": "Hohe Qualität", - "translateComplete.segments": "Segmente", - "translateComplete.characters": "Zeichen", - "translateComplete.confidence": "Vertrauen", - "providerTheme.deepseek.badge": "Essenziell", - "providerTheme.deepseek.subBadge": "Technisch & Sparsam", - "providerTheme.deepseek.desc": "Ultrapräzise und wirtschaftliche Übersetzung, ideal für technische Dokumente und Code.", - "providerTheme.openai.badge": "Premium", - "providerTheme.openai.subBadge": "Hohe Treue", - "providerTheme.openai.desc": "Der globale KI-Standard. Maximale Textkonsistenz und strenge Stileinhaltung.", - "providerTheme.minimax.badge": "Erweitert", - "providerTheme.minimax.subBadge": "Leistung", - "providerTheme.minimax.desc": "Unglaubliche Ausführungsgeschwindigkeit und ausgezeichnetes Verständnis komplexer Strukturen.", - "providerTheme.openrouter.badge": "Express", - "providerTheme.openrouter.subBadge": "Multi-Modell", - "providerTheme.openrouter.desc": "Einheitlicher Zugriff auf die besten Open-Source-Modelle, optimiert für Übersetzung.", - "providerTheme.openrouter_premium.badge": "Ultra", - "providerTheme.openrouter_premium.subBadge": "Maximaler Kontext", - "providerTheme.openrouter_premium.desc": "Unterstützt durch modernste Modelle (GPT-4o, Claude Sonnet 4.6) für lange Dokumente.", - "providerTheme.zai.badge": "Spezialisiert", - "providerTheme.zai.subBadge": "Finanzen & Recht", - "providerTheme.zai.desc": "Modell feinabgestimmt auf anspruchsvolle Geschäftsterminologien (Recht, Finanzen).", - "providerTheme.default.badge": "Modern", - "providerTheme.default.subBadge": "KI-Argumentation", - "providerTheme.default.desc": "Großsprachmodell-Übersetzung (LLM) mit fortgeschrittener semantischer Analyse.", - "providerTheme.classic.google.label": "Google Übersetzer", - "providerTheme.classic.google.desc": "Ultraschnelle Übersetzung für über 130 Sprachen. Empfohlen für allgemeine Abläufe.", - "providerTheme.classic.deepl.label": "DeepL Pro", - "providerTheme.classic.deepl.desc": "Hochpräzise Übersetzung, bekannt für Flüssigkeit und natürliche Formulierungen.", - "providerTheme.classic.google_cloud.label": "Google Cloud API", - "providerTheme.classic.google_cloud.desc": "Professionelle Cloud-Engine, optimiert für die Verarbeitung großer Dokumentenmengen.", - "providerSelector.noClassic": "Kein Standard-Übersetzer verfügbar.", - "providerSelector.noLlm": "Kein KI-Modell konfiguriert.", - "providerSelector.costOne": "Kosten: 1 Guthaben pro Seite", - "providerSelector.costFive": "Kosten: 5 Guthaben pro Seite (Premium-Faktor)", - "providerSelector.unlockContextual": "Premium-Kontextübersetzung für Ihre gesamten Dokumente freischalten.", - "translate.header.processing": "Verarbeitung läuft", - "translate.header.aiActive": "KI-Analyse aktiv", - "translate.header.aiActiveDesc": "Ihr Layout wird von unserer kontextuellen Engine beibehalten.", - "translate.header.completed": "Abgeschlossen", - "translate.header.completedTitle": "Übersetzung abgeschlossen", - "translate.header.proSpace": "Pro-Bereich", - "translate.header.translateDoc": "Dokument übersetzen", - "translate.header.translateDocDesc": "Behalten Sie das Originallayout mit unserer Ultra-High-Fidelity-Übersetzungs-Engine.", - "translate.upload.nativeFormat": "Natives Format", - "translate.fileType.word": "Word (.docx)", - "translate.fileType.excel": "Excel (.xlsx)", - "translate.fileType.slides": "Folien (.pptx)", - "translate.fileType.pdf": "PDF (.pdf)", - "translate.startTranslation": "Übersetzung starten", - "translate.submit": "Wird gesendet…", - "translate.chooseTargetLang": "Bitte wählen Sie eine Zielsprache", - "translate.pleaseLoadFile": "Bitte laden Sie zuerst eine Datei hoch", - "translate.contextEngineActive": "Kontextuelle Engine aktiv", - "translate.phase1": "Phase 1: Initialisierung", - "translate.phase2": "Phase 2: Kontextuelle Rekonstruktion", - "translate.stat.segments": "Segmente", - "translate.stat.precision": "Genauigkeit", - "translate.stat.speedLabel": "Geschwindigkeit", - "translate.stat.turbo": "Turbo", - "translate.stat.time": "Zeit", - "translate.complete.masterQuality": "✓ Meister-Qualität", - "translate.download": "Herunterladen", - "translate.newTranslation": "+ Neue Übersetzung", - "translate.failedTitle": "Übersetzungsfehler", - "translate.retry": "Erneut versuchen", - "translate.uploadAnother": "Andere Datei hochladen", - "translate.monitor": "KI-Monitor", - "translate.summary": "Zusammenfassung", - "translate.cancelProcess": "⟳ Prozess abbrechen", - "translate.layoutIntegrity": "Layout-Integrität", - "translate.secureHundred": "100% SICHER", - "translate.okHundred": "100% OK", - "translate.preserveLayout": "Layout beibehalten", - "translate.preserveLayoutDesc": "Layout beibehalten", - "translate.textOnly": "Nur Text", - "translate.textOnlyDesc": "Schnelle Übersetzung nur des Textes", - "translate.unavailableStandard": "Im Standardmodus nicht verfügbar (nur KI)", - "apiKeys.noKeysGenerated": "Keine Schlüssel generiert", - "apiKeys.copied": "Kopiert!", - "services.fallback.google.label": "Google Übersetzer", - "services.fallback.google.desc": "Schnelle Übersetzung, über 130 Sprachen", - "settings.formats.excel.name": "Excel", - "settings.formats.word.name": "Word", - "settings.formats.powerpoint.name": "PowerPoint", - "pricing.dashboard": "Dashboard", - "pricing.okSymbol": "✓", - "pricing.errSymbol": "✕", - }, - // ═══════════════════════════════════════════════════════════════ - // PORTUGUESE – BRAZILIAN (pt) - // ═══════════════════════════════════════════════════════════════ - pt: { - "auth.brandName": "Wordly", - "dashboard.nav.translate": "Traduzir", - "dashboard.nav.profile": "Meu perfil", - "dashboard.nav.settings": "Configurações", - "dashboard.nav.context": "Contexto", - "dashboard.nav.services": "Serviços", - "dashboard.nav.apiKeys": "Chaves de API", - "dashboard.nav.glossaries": "Glossários", - "dashboard.header.title": "Painel", - "dashboard.header.subtitle": "Gerencie suas traduções", - "dashboard.header.toggleMenu": "Menu", - "dashboard.header.profileTitle": "Meu perfil", - "dashboard.sidebar.theme": "Tema", - "dashboard.sidebar.signOut": "Sair", - "dashboard.sidebar.backHome": "Voltar ao início", - "dashboard.sidebar.upgradeToPro": "Atualizar para Pro →", - "cookieConsent.title": "Cookies no Wordly", - "cookieConsent.description": "Usamos cookies essenciais para o funcionamento do serviço (sessão, segurança, idioma). Com a sua permissão, também usamos cookies opcionais para medir o tráfego e melhorar o produto.", - "cookieConsent.acceptAll": "Aceitar todas", - "cookieConsent.essentialOnly": "Apenas essenciais", - "cookieConsent.learnMore": "Saiba mais", - "landing.nav.why": "Por que nós?", - "landing.nav.formats": "Formatos", - "landing.nav.pricing": "Preços", - "landing.nav.login": "Entrar", - "landing.nav.startFree": "Teste grátis", - "landing.hero.tag": "IA Documental Profissional", - "landing.hero.titleLine1": "Traduza seus documentos.", - "landing.hero.titleLine2": "Com formatação perfeita.", - "landing.hero.description": "O único tradutor que preserva SmartArt, gráficos, sumários, formas e layouts complexos — exatamente como eram.", - "landing.hero.ctaMain": "Teste grátis — 2 docs/mês", - "landing.hero.ctaSec": "Ver ofertas", - "landing.hero.deleted": "Arquivos excluídos após 60 min", - "landing.hero.noHidden": "Sem taxas ocultas", - "landing.hero.preview": "Visualização antes do pagamento", - "landing.hero.formattedOk": "Formatação OK", - "landing.hero.aiActive": "Tradução IA ativa", - "landing.steps.title": "Como funciona?", - "landing.steps.subtitle": "Três passos. Zero perda de formato.", - "landing.steps.step1.num": "01", - "landing.steps.step1.title": "Envie seu arquivo", - "landing.steps.step1.desc": "Arraste e solte seu documento Excel, Word, PowerPoint ou PDF.", - "landing.steps.step2.num": "02", - "landing.steps.step2.title": "Escolha idioma e motor", - "landing.steps.step2.desc": "Selecione o idioma de destino e o motor — clássico ou IA contextual.", - "landing.steps.step3.num": "03", - "landing.steps.step3.title": "Baixe o resultado", - "landing.steps.step3.desc": "Receba seu documento traduzido com formatação idêntica ao original.", - "landing.features.tag": "Motor de Tradução IA", - "landing.features.title": "Uma tradução que entende o seu ofício", - "landing.features.description": "Nossos modelos de IA analisam o contexto, respeitam sua terminologia e até traduzem texto dentro de imagens.", - "landing.features.context.title": "Contexto setorial", - "landing.features.context.desc": "Descreva seu setor e receba traduções adaptadas, não genéricas.", - "landing.features.glossary.title": "Glossários setoriais", - "landing.features.glossary.desc": "Defina seus termos técnicos. CTA será «Unidade de Tratamento de Ar», nunca «Chamada para Ação».", - "landing.features.vision.title": "Visão de imagens", - "landing.features.vision.desc": "Texto incorporado em imagens, diagramas e gráficos é detectado e traduzido.", - "landing.features.demo.source": "Origem (FR)", - "landing.features.demo.google": "Google Translate", - "landing.features.demo.ours": "Nossa IA", - "landing.layout.title": "Sua formatação,", - "landing.layout.title2": "perfeitamente preservada", - "landing.layout.subtitle": "Outros tradutores quebram seu layout. Nós não.", - "landing.layout.p1.title": "SmartArt e diagramas", - "landing.layout.p1.desc": "Organogramas, fluxogramas, hierarquias — tudo traduzido de forma idêntica.", - "landing.layout.p2.title": "Sumários", - "landing.layout.p2.desc": "Entradas do sumário, números de página e referências cruzadas atualizados corretamente.", - "landing.layout.p3.title": "Gráficos e diagramas", - "landing.layout.p3.desc": "Títulos, rótulos de eixos, legendas e nomes de séries — tudo traduzido.", - "landing.layout.p4.title": "Formas e caixas de texto", - "landing.layout.p4.desc": "Retângulos, blocos arredondados, balões — localizados em todo lugar.", - "landing.layout.p5.title": "Cabeçalhos e rodapés", - "landing.layout.p5.desc": "Cabeçalhos, rodapés e notas de rodapé nunca são esquecidos.", - "landing.layout.p6.title": "130+ idiomas", - "landing.layout.p6.desc": "Google Tradutor, DeepL e motores de IA de nível profissional.", - "landing.formats.title": "Cada formato,", - "landing.formats.title2": "cada elemento", - "landing.formats.subtitle": "Traduzimos o que os outros esquecem. Sua empresa merece documentação impecável.", - "landing.formats.word.name": "Word", - "landing.formats.word.i1": "Parágrafos e títulos", - "landing.formats.word.i2": "Tabelas e gráficos", - "landing.formats.word.i3": "Diagramas SmartArt", - "landing.formats.word.i4": "Sumário", - "landing.formats.word.i5": "Cabeçalhos e rodapés", - "landing.formats.word.i6": "Formas e caixas de texto", - "landing.formats.word.i7": "Notas de rodapé e finais", - "landing.formats.excel.name": "Excel", - "landing.formats.excel.i1": "Valores de células", - "landing.formats.excel.i2": "Nomes de planilhas", - "landing.formats.excel.i3": "Gráficos e rótulos", - "landing.formats.excel.i4": "Cabeçalhos e rodapés", - "landing.formats.excel.i5": "Células mescladas preservadas", - "landing.formats.pptx.name": "PowerPoint", - "landing.formats.pptx.i1": "Texto de slides e notas", - "landing.formats.pptx.i2": "Gráficos e diagramas", - "landing.formats.pptx.i3": "Formas e caixas de texto", - "landing.formats.pptx.i4": "Layouts mestres", - "landing.formats.pptx.i5": "Animações preservadas", - "landing.formats.pdf.name": "PDF", - "landing.formats.pdf.i1": "PDFs baseados em texto", - "landing.formats.pdf.i2": "Layout preservado", - "landing.formats.pdf.i3": "Imagens mantidas no lugar", - "landing.formats.pdf.i4": "Tabelas mantidas", - "landing.formats.pdf.i5": "Saída como DOCX ou PDF", - "landing.pricing.title": "Preços simples e honestos", - "landing.pricing.subtitle": "O que você vê é o que você paga. Sem taxas ocultas.", - "landing.pricing.monthly": "Mensal", - "landing.pricing.annual": "Anual", - "landing.pricing.bestValue": "Mais popular", - "landing.pricing.month": "/mês", - "landing.pricing.footer": "O preço exibido é o preço que você paga. Sem taxas ocultas após a tradução.", - "landing.pricing.starter.name": "Starter", - "landing.pricing.starter.desc": "Para pessoas físicas e projetos pequenos", - "landing.pricing.starter.f1": "50 documentos / mês", - "landing.pricing.starter.f2": "Até 50 páginas por doc", - "landing.pricing.starter.f3": "Google Tradutor + DeepL", - "landing.pricing.starter.f4": "Arquivos de até 10 MB", - "landing.pricing.starter.cta": "Começar", - "landing.pricing.pro.name": "Pro", - "landing.pricing.pro.desc": "Para profissionais exigentes", - "landing.pricing.pro.f1": "200 documentos / mês", - "landing.pricing.pro.f2": "Até 200 páginas por doc", - "landing.pricing.pro.f3": "Tradução com IA", - "landing.pricing.pro.f4": "Google + DeepL incluídos", - "landing.pricing.pro.f5": "Glossários e prompts personalizados", - "landing.pricing.pro.f6": "Suporte prioritário", - "landing.pricing.pro.cta": "Testar Pro", - "landing.pricing.business.name": "Business", - "landing.pricing.business.desc": "Para equipes com alto volume", - "landing.pricing.business.f1": "1 000 documentos / mês", - "landing.pricing.business.f2": "Até 500 páginas por doc", - "landing.pricing.business.f3": "IA Premium (Claude)", - "landing.pricing.business.f4": "Todos os provedores + API", - "landing.pricing.business.f5": "Webhooks e automação", - "landing.pricing.business.f6": "5 assentos de equipe", - "landing.pricing.business.cta": "Fale conosco", - "landing.cta.title": "Comece a traduzir em 30 segundos", - "landing.cta.subtitle": "Nenhum cartão de crédito necessário. Experimente grátis agora e dê vida aos seus documentos multilíngues.", - "landing.cta.button": "Criar conta gratuita", - "landing.cta.secure": "Protegido por criptografia AES-256", - "landing.footer.desc": "Especialista em tradução inteligente de documentos. Combinamos a arte do layout com a ciência da IA contextual.", - "landing.footer.product": "Produto", - "landing.footer.resources": "Recursos", - "landing.footer.legal": "Legal", - "landing.footer.rights": "© 2026 Wordly.art — Todos os direitos reservados.", - "dashboard.translate.pageTitle": "Traduzir um documento", - "dashboard.translate.pageSubtitle": "Importe um arquivo e escolha o idioma de destino", - "dashboard.translate.errorNotificationTitle": "Erro", - "dashboard.translate.dropzone.uploadAria": "Área para soltar arquivos", - "dashboard.translate.dropzone.title": "Arraste e solte seu arquivo aqui", - "dashboard.translate.dropzone.subtitle": "ou clique para selecionar (DOCX, XLSX, PPTX, PDF)", - "dashboard.translate.dropzone.replaceFile": "Substituir arquivo", - "dashboard.translate.language.source": "Idioma de origem", - "dashboard.translate.language.target": "Idioma de destino", - "dashboard.translate.language.loading": "Carregando idiomas…", - "dashboard.translate.language.autoDetect": "Detecção automática", - "dashboard.translate.language.selectPlaceholder": "Selecionar…", - "dashboard.translate.language.loadErrorPrefix": "Erro ao carregar os idiomas", - "dashboard.translate.provider.loading": "Carregando provedores…", - "dashboard.translate.provider.noneConfigured": "Nenhum provedor configurado", - "dashboard.translate.provider.modelTitle": "Modelo", - "dashboard.translate.provider.sectionTitle": "Provedor", - "dashboard.translate.provider.llmDivider": "IA · Contextual", - "dashboard.translate.provider.llmDividerPro": "IA · Contextual (Pro)", - "dashboard.translate.provider.upgrade": "Fazer upgrade para Pro", - "dashboard.translate.provider.upgradeSuffix": "para desbloquear a tradução por IA", - "dashboard.translate.trust.zeroRetention": "Zero retenção", - "dashboard.translate.trust.deletedAfter": "Arquivos excluídos após o processamento", - "dashboard.translate.actions.uploading": "Enviando…", - "dashboard.translate.actions.translate": "Traduzir", - "dashboard.translate.actions.filePrefix": "Arquivo: ", - "dashboard.translate.actions.cancel": "Cancelar", - "dashboard.translate.actions.tryAgain": "Tentar novamente", - "dashboard.translate.steps.uploading": "Enviando arquivo…", - "dashboard.translate.steps.starting": "Iniciando tradução…", - "dashboard.translate.complete.title": "Tradução concluída!", - "dashboard.translate.complete.descNamed": "Seu arquivo {name} foi traduzido com sucesso.", - "dashboard.translate.complete.descGeneric": "Seu arquivo foi traduzido com sucesso.", - "dashboard.translate.complete.downloading": "Baixando…", - "dashboard.translate.complete.download": "Baixar", - "dashboard.translate.complete.newTranslation": "Nova tradução", - "dashboard.translate.complete.toastOkTitle": "Sucesso", - "dashboard.translate.complete.toastOkDesc": "{name} foi baixado com sucesso.", - "dashboard.translate.complete.toastFailTitle": "Falha", - "dashboard.translate.complete.toastFailDesc": "A tradução falhou. Por favor, tente novamente.", - "dashboard.translate.sourceDocument": "Documento fonte", - "dashboard.translate.configuration": "Configuração", - "dashboard.translate.translating": "Tradução em andamento", - "dashboard.translate.liveMonitor": "Monitor em tempo real", - "dashboard.translate.summary": "Resumo", - "dashboard.translate.engine": "Motor", - "dashboard.translate.confidence": "Confiança", - "dashboard.translate.cancel": "Cancelar", - "dashboard.translate.segments": "Segmentos", - "dashboard.translate.characters": "Caracteres", - "dashboard.translate.elapsed": "Decorrido", - "dashboard.translate.segPerMin": "Seg/min", - "dashboard.translate.highQuality": "Alta qualidade", - "dashboard.translate.quality": "Qualidade", - "dashboard.translate.completed": "Tradução concluída", - "dashboard.translate.replace": "Substituir", - "dashboard.translate.pdfMode.title": "Modo de tradução PDF", - "dashboard.translate.pdfMode.preserveLayout": "Preservar layout", - "dashboard.translate.pdfMode.textOnly": "Apenas texto", - "dashboard.translate.pdfMode.preserveLayoutDesc": "Mantém imagens, tabelas e formatação. Ideal para PDFs simples.", - "dashboard.translate.pdfMode.textOnlyDesc": "Traduz todo o texto perfeitamente. Saída limpa, sem problemas de layout.", - "dashboard.translate.pipeline.upload": "Enviar", - "dashboard.translate.pipeline.analyze": "Analisar", - "dashboard.translate.pipeline.translate": "Tradução", - "dashboard.translate.pipeline.rebuild": "Reconstruir", - "dashboard.translate.pipeline.finalize": "Finalizar", - "dashboard.translate.progress.processingFallback": "A processar…", - "dashboard.translate.progress.connectionLost": "Conexão perdida. A tentar novamente…", - "dashboard.translate.progress.failedTitle": "Tradução falhou", - "dashboard.translate.error.unexpected": "Ocorreu um erro inesperado. Tente novamente.", - "dashboard.translate.error.noResult": "A tradução não produziu resultados. Verifique se o documento contém texto e tente novamente ou escolha outro motor.", - "dashboard.translate.error.apiKey": "Chave de API inválida ou ausente. Contacte o administrador para configurar as chaves.", - "dashboard.translate.error.quota": "Limite de uso atingido. Tente novamente em alguns minutos ou escolha outro motor.", - "dashboard.translate.error.timeout": "A conexão ao serviço de tradução expirou. Verifique a sua rede e tente novamente.", - "dashboard.translate.error.sessionExpired": "Sessão expirada. Clique em Repetir para reiniciar a tradução.", - "dashboard.translate.error.empty": "O documento parece estar vazio ou não contém texto traduzível (PDF digitalizado?).", - "dashboard.translate.error.unsupported": "Formato de ficheiro não suportado ou ficheiro corrompido.", - "dashboard.translate.error.connection": "Conexão perdida. Verifique a sua rede e tente novamente.", - "dashboard.translate.error.generic": "Tradução falhou: {detail}", - "dashboard.translate.error.title": "Tradução falhou", - "dashboard.translate.retry": "Tentar novamente", - "dashboard.translate.newFile": "Novo ficheiro", - "dashboard.translate.modeAI": "Modo IA", - "dashboard.translate.modeClassic": "Modo Clássico", - "dashboard.translate.glossaryLLMHint": "Glossários disponíveis no modo IA", - "dashboard.translate.submitting": "A enviar...", - "dashboard.translate.submit": "Iniciar tradução", - "dashboard.translate.noFile": "Carregue um ficheiro primeiro", - "dashboard.translate.noTargetLang": "Selecione um idioma de destino", - "glossaries.yourGlossaries": "Seus glossários", - "glossaries.title": "Glossários e Contexto", - "glossaries.description": "Gerencie seus glossários e instruções de contexto para traduções mais precisas.", - "glossaries.createNew": "Criar novo", - "glossaries.empty": "Nenhum glossário", - "glossaries.emptyDesc": "Crie seu primeiro glossário ou carregue um preset profissional acima", - "glossaries.defineTerms": "termos", - "glossaries.aboutTitle": "Sobre glossários", - "glossaries.aboutDesc": "Os glossários permitem definir traduções exatas para termos específicos. Ao traduzir, os termos do glossário garantem traduções consistentes e precisas.", - "glossaries.aboutFormat": "Cada termo tem uma palavra fonte e traduções em vários idiomas. Selecione um glossário na página de tradução para aplicá-lo.", - "glossaries.toast.created": "Glossário criado", - "glossaries.toast.createdDesc": "O glossário \"{name}\" foi criado.", - "glossaries.toast.imported": "Glossário importado", - "glossaries.toast.importedDesc": "O glossário \"{name}\" foi importado.", - "glossaries.toast.updated": "Glossário atualizado", - "glossaries.toast.updatedDesc": "O glossário \"{name}\" foi atualizado.", - "glossaries.toast.deleted": "Glossário excluído", - "glossaries.toast.deletedDesc": "O glossário foi excluído.", - "glossaries.toast.error": "Erro", - "glossaries.toast.errorCreate": "Falha ao criar glossário", - "glossaries.toast.errorImport": "Falha ao importar glossário", - "glossaries.toast.errorUpdate": "Falha ao atualizar glossário", - "glossaries.toast.errorDelete": "Falha ao excluir glossário", - "glossaries.dialog.title": "Novo glossário", - "glossaries.dialog.description": "Crie um glossário para suas traduções", - "glossaries.dialog.nameLabel": "Nome", - "glossaries.dialog.namePlaceholder": "Meu glossário", - "glossaries.dialog.tabTemplates": "Modelos", - "glossaries.dialog.tabFile": "Arquivo", - "glossaries.dialog.tabManual": "Manual", - "glossaries.dialog.cancel": "Cancelar", - "glossaries.dialog.creating": "Criando…", - "glossaries.dialog.importing": "Importando…", - "glossaries.dialog.importBtn": "Importar", - "glossaries.dialog.selectPrompt": "Selecionar", - "glossaries.dialog.createBtn": "Criar", - "glossaries.dialog.createEmpty": "Criar vazio", - "glossaries.dialog.terms": "termos", - "glossaries.dialog.templatesDesc": "Escolha um modelo predefinido", - "glossaries.dialog.templatesEmpty": "Nenhum modelo disponível", - "glossaries.dialog.dropTitle": "Arraste um arquivo CSV aqui", - "glossaries.dialog.dropOr": "ou", - "glossaries.dialog.dropFormats": "CSV, TSV, TXT", - "glossaries.termEditor.addTerm": "Adicionar termo", - "glossaries.termEditor.maxReached": "Máximo de {max} termos por glossário atingido.", - "glossaries.dialog.formatTitle": "Formato", - "glossaries.dialog.formatDesc": "origem,destino (um por linha)", - "glossaries.dialog.formatNote": "Primeira linha ignorada se houver cabeçalho", - "glossaries.dialog.errorFormat": "Formato não suportado", - "glossaries.dialog.errorSize": "Arquivo muito grande", - "glossaries.dialog.errorEmpty": "Arquivo vazio", - "glossaries.dialog.errorRead": "Erro de leitura", - "glossaries.dialog.parsing": "Analisando…", - "glossaries.dialog.termsImported": "termos importados", - "glossaries.dialog.changeFile": "Trocar arquivo", - "glossaries.dialog.retry": "Tentar novamente", - "glossaries.edit.title": "Modifier le glossaire", - "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", - "glossaries.edit.nameLabel": "Nom du glossaire", - "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", - "glossaries.edit.sourceLang": "Langue source", - "glossaries.edit.targetLang": "Langue cible", - "glossaries.edit.termsLabel": "Termes ({count} valides)", - "glossaries.edit.exportCsv": "Exporter CSV", - "glossaries.edit.importCsv": "Importer CSV", - "glossaries.edit.cancel": "Annuler", - "glossaries.edit.saving": "Enregistrement...", - "glossaries.edit.saveChanges": "Enregistrer les modifications", - "glossaries.edit.importFailedTitle": "Échec de l'importation", - "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", - "glossaries.edit.importSuccessTitle": "Importation réussie", - "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", - "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", - "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", - "glossaries.delete.title": "Supprimer le glossaire", - "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", - "glossaries.delete.warning": "Cette action est irréversible", - "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", - "glossaries.delete.cancel": "Annuler", - "glossaries.delete.deleting": "Suppression...", - "glossaries.delete.deleteBtn": "Supprimer", - "glossaries.upgrade.title": "Glossaires", - "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", - "glossaries.upgrade.feature1": "Créez plusieurs glossaires", - "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", - "glossaries.upgrade.feature3": "Importez/exportez via CSV", - "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", - "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", - "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", - "glossaries.upgrade.proLabel": "Pro", - "glossaries.upgrade.upgradeBtn": "Passer à Pro", - "glossaries.loading": "Chargement...", - "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", - "glossaries.howItWorks.step1Title": "Configurez ici", - "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", - "glossaries.howItWorks.step2Title": "Activez dans Traduire", - "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", - "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", - "glossaries.howItWorks.goToTranslate": "Aller à Traduire", - "glossaries.status.unsaved": "Non enregistré", - "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", - "glossaries.status.inactive": "Inactif", - "glossaries.instructions.whatForBold": "À quoi ça sert ?", - "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", - "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", - "glossaries.instructions.charCount": "{count} caractères", - "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", - "glossaries.instructions.clearAll": "Tout effacer", - "glossaries.instructions.saving": "Enregistrement…", - "glossaries.instructions.saved": "Enregistré", - "glossaries.presets.whatForBold": "À quoi ça sert ?", - "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", - "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", - "glossaries.presets.creating": "Création…", - "glossaries.presets.alreadyImported": "Déjà importé", - "glossaries.presets.it.title": "IT / Logiciel", - "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", - "glossaries.presets.legal.title": "Juridique / Contrats", - "glossaries.presets.legal.desc": "Droit des affaires, contentieux", - "glossaries.presets.medical.title": "Médical / Santé", - "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", - "glossaries.presets.finance.title": "Finance / Comptabilité", - "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", - "glossaries.presets.marketing.title": "Marketing / Publicité", - "glossaries.presets.marketing.desc": "Digital, branding, analytics", - "glossaries.presets.hr.title": "RH / Ressources Humaines", - "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", - "glossaries.presets.scientific.title": "Scientifique / Recherche", - "glossaries.presets.scientific.desc": "Publications, thèses, articles", - "glossaries.presets.ecommerce.title": "E-commerce / Vente", - "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", - "glossaries.grid.title": "Vos", - "glossaries.grid.titleHighlight": "glossaires", - "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", - "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", - "glossaries.grid.activeTranslation": "Traduction active :", - "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", - "glossaries.badge.compatible": "Compatible", - "glossaries.badge.otherTarget": "Autre cible", - "glossaries.card.editTerms": "Modifier les termes", - "glossaries.card.created": "Criado", - "glossaries.card.term": "termo", - "glossaries.card.delete": "Supprimer", - "glossaries.grid.searchPlaceholder": "Search a glossary…", - "glossaries.grid.noResults": "No results for this search.", - "glossaries.detail.backToList": "Back to glossaries", - "glossaries.detail.save": "Save", - "glossaries.detail.savedTitle": "Saved", - "glossaries.detail.savedDesc": "The glossary has been updated.", - "glossaries.detail.settingsTitle": "Settings", - "glossaries.detail.sourceLang": "Source language", - "glossaries.detail.targetLang": "Target language", - "glossaries.detail.termsTitle": "Terms", - "glossaries.detail.terms": "terms", - "glossaries.detail.searchTerms": "Filter…", - "glossaries.detail.noTerms": "No terms yet.", - "glossaries.detail.addFirstTerm": "Add the first term", - "glossaries.detail.addTerm": "Add a term", - "glossaries.detail.maxReached": "Maximum limit reached", - "glossaries.detail.source": "Source", - "glossaries.detail.target": "Target", - "glossaries.detail.sourcePlaceholder": "source term", - "glossaries.detail.targetPlaceholder": "target term", - "glossaries.detail.csvTitle": "CSV", - "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", - "glossaries.detail.export": "Export", - "glossaries.detail.import": "Import", - "glossaries.detail.dangerTitle": "Danger zone", - "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", - "glossaries.detail.deleteGlossary": "Delete this glossary", - "glossaries.detail.confirmDelete": "Confirm deletion?", - "glossaries.detail.confirm": "Confirm", - "glossaries.detail.cancel": "Cancel", - "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", - "glossaries.detail.sourceLocked": "fixed", - "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", - "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", - "glossaries.detail.notFoundTitle": "Glossary not found", - "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", - "glossaries.detail.maxTermsTitle": "Limit reached", - "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", - "glossaries.detail.importEmptyTitle": "Empty file", - "glossaries.detail.importEmptyDesc": "No terms detected in this file.", - "glossaries.detail.importedTitle": "Imported", - "glossaries.detail.importedDesc": "{count} terms imported.", - "glossaries.detail.importErrorTitle": "Read error", - "glossaries.detail.importErrorDesc": "Unable to read the file.", - "apiKeys.webhook.title": "Intégration Webhook", - "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", - "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", - "apiKeys.webhook.codeParam": "webhook_url", - "translate.mode.label": "Mode de traduction", - "translate.mode.classic": "Classique", - "translate.mode.classicDesc": "Rapide", - "translate.mode.proLlm": "Pro LLM", - "translate.mode.proLlmDesc": "Contextuel", - "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", - "translate.mode.upgradeLink": "Passer à Pro", - "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", - "pricing.nav.back": "Voltar", - "pricing.nav.home": "Início", - "pricing.nav.mySubscription": "Minha assinatura", - "pricing.header.badge": "Modelos de IA atualizados — Março 2026", - "pricing.header.title": "Um plano para cada necessidade", - "pricing.header.subtitle": "Traduza seus documentos Word, Excel e PowerPoint preservando a formatação original. Sem necessidade de chave de API.", - "pricing.billing.monthly": "Mensal", - "pricing.billing.yearly": "Anual", - "pricing.plans.free.name": "Gratuito", - "pricing.plans.starter.name": "Starter", - "pricing.plans.pro.name": "Pro", - "pricing.plans.business.name": "Business", - "pricing.plans.enterprise.name": "Enterprise", - "pricing.plans.free.description": "Perfeito para conhecer o aplicativo", - "pricing.plans.starter.description": "Para pessoas físicas e projetos pequenos", - "pricing.plans.pro.description": "Para profissionais e equipes em crescimento", - "pricing.plans.business.description": "Para equipes e organizações", - "pricing.plans.enterprise.description": "Soluções personalizadas para grandes organizações", - "pricing.plans.pro.highlight": "Mais popular", - "pricing.plans.pro.badge": "POPULAR", - "pricing.plans.enterprise.badge": "SOB CONSULTA", - "pricing.plans.free.feat1": "5 documentos / mês", - "pricing.plans.free.feat2": "Até 15 páginas por documento", - "pricing.plans.free.feat3": "Google Tradutor incluído", - "pricing.plans.free.feat4": "Todos os idiomas (130+)", - "pricing.plans.free.feat5": "Suporte da comunidade", - "pricing.plans.starter.feat1": "50 documentos / mês", - "pricing.plans.starter.feat2": "Até 50 páginas por documento", - "pricing.plans.starter.feat3": "Google Tradutor + DeepL", - "pricing.plans.starter.feat4": "Arquivos de até 10 MB", - "pricing.plans.starter.feat5": "Suporte por e-mail", - "pricing.plans.starter.feat6": "Histórico de 30 dias", - "pricing.plans.pro.feat1": "200 documentos / mês", - "pricing.plans.pro.feat2": "Até 200 páginas por documento", - "pricing.plans.pro.feat3": "Tradução IA Essencial", - "pricing.plans.pro.feat4": "Google Tradutor + DeepL", - "pricing.plans.pro.feat5": "Arquivos de até 25 MB", - "pricing.plans.pro.feat6": "Glossários personalizados", - "pricing.plans.pro.feat7": "Suporte prioritário", - "pricing.plans.pro.feat8": "Histórico de 90 dias", - "pricing.plans.business.feat1": "1 000 documentos / mês", - "pricing.plans.business.feat2": "Até 500 páginas por documento", - "pricing.plans.business.feat3": "IA Essencial + Premium (Claude Haiku)", - "pricing.plans.business.feat4": "Todos os provedores de tradução", - "pricing.plans.business.feat5": "Arquivos de até 50 MB", - "pricing.plans.business.feat6": "Acesso à API (10 000 chamadas/mês)", - "pricing.plans.business.feat7": "Webhooks de notificação", - "pricing.plans.business.feat8": "Suporte dedicado", - "pricing.plans.business.feat9": "Histórico de 1 ano", - "pricing.plans.business.feat10": "Análises avançadas", - "pricing.plans.enterprise.feat1": "Documentos ilimitados", - "pricing.plans.enterprise.feat2": "Todos os modelos de IA (GPT-5, Claude Opus 4.6…)", - "pricing.plans.enterprise.feat3": "Implantação local ou em nuvem dedicada", - "pricing.plans.enterprise.feat4": "SLA 99,9 % garantido", - "pricing.plans.enterprise.feat5": "Suporte dedicado 24/7", - "pricing.plans.enterprise.feat6": "Marca branca (white-label)", - "pricing.plans.enterprise.feat7": "Equipes ilimitadas", - "pricing.plans.enterprise.feat8": "Integrações personalizadas", - "pricing.card.onRequest": "Sob consulta", - "pricing.card.free": "Gratuito", - "pricing.card.perMonth": "/mês", - "pricing.card.billedYearly": "Cobrado {price} € / ano", - "pricing.card.documents": "Documentos", - "pricing.card.pagesMax": "Páginas máx.", - "pricing.card.aiTranslation": "Tradução por IA", - "pricing.card.unlimited": "Ilimitado", - "pricing.card.perMonthStat": "/ mês", - "pricing.card.perDoc": "p / doc", - "pricing.card.aiEssential": "Essencial", - "pricing.card.aiEssentialPremium": "Essencial + Premium", - "pricing.card.aiCustom": "Personalizado", - "pricing.card.myPlan": "Meu plano", - "pricing.card.managePlan": "Gerenciar meu plano", - "pricing.card.startFree": "Começar gratuitamente", - "pricing.card.contactUs": "Fale conosco", - "pricing.card.choosePlan": "Escolher este plano", - "pricing.card.processing": "Processando…", - "pricing.comparison.title": "Comparação detalhada", - "pricing.comparison.subtitle": "Tudo incluído em cada plano", - "pricing.comparison.feature": "Recurso", - "pricing.comparison.docsPerMonth": "Documentos / mês", - "pricing.comparison.pagesMaxPerDoc": "Páginas máx. / documento", - "pricing.comparison.maxFileSize": "Tamanho máx. de arquivo", - "pricing.comparison.googleTranslation": "Google Tradutor", - "pricing.comparison.deepl": "DeepL", - "pricing.comparison.aiEssential": "Tradução IA Essencial", - "pricing.comparison.aiPremium": "Tradução IA Premium", - "pricing.comparison.apiAccess": "Acesso à API", - "pricing.comparison.priorityProcessing": "Processamento prioritário", - "pricing.comparison.support": "Suporte", - "pricing.comparison.support.community": "Comunidade", - "pricing.comparison.support.email": "E-mail", - "pricing.comparison.support.priority": "Prioritário", - "pricing.comparison.support.dedicated": "Dedicado", - "pricing.comparison.mb": "MB", - "pricing.credits.title": "Créditos adicionais", - "pricing.credits.subtitle": "Precisa de mais? Compre créditos avulsos, sem assinatura.", - "pricing.credits.perPage": "1 crédito = 1 página traduzida.", - "pricing.credits.bestValue": "Melhor custo-benefício", - "pricing.credits.unit": "créditos", - "pricing.credits.centsPerCredit": "cts / crédito", - "pricing.credits.buy": "Comprar", - "pricing.trust.encryption.title": "Criptografia de ponta a ponta", - "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 em repouso", - "pricing.trust.languages.title": "130+ idiomas", - "pricing.trust.languages.sub": "Incluindo árabe, persa, hebraico (RTL)", - "pricing.trust.parallel.title": "Processamento paralelo", - "pricing.trust.parallel.sub": "IA multi-thread ultrarrápida", - "pricing.trust.availability.title": "Disponível 24/7", - "pricing.trust.availability.sub": "99,9 % de uptime garantido", - "pricing.aiModels.title": "Nossos modelos de IA — Março 2026", - "pricing.aiModels.essential.title": "Tradução IA Essencial", - "pricing.aiModels.essential.plan": "Plano Pro", - "pricing.aiModels.essential.descPrefix": "Baseado em", - "pricing.aiModels.essential.descSuffix": "— o modelo de IA mais econômico de 2026. Qualidade comparável a modelos frontier a uma fração do custo.", - "pricing.aiModels.essential.modelName": "nosso modelo IA Essencial", - "pricing.aiModels.essential.context": "163K tokens de contexto", - "pricing.aiModels.essential.value": "Excelente custo-benefício", - "pricing.aiModels.premium.title": "Tradução IA Premium", - "pricing.aiModels.premium.plan": "Plano Business", - "pricing.aiModels.premium.descPrefix": "Baseado em", - "pricing.aiModels.premium.descSuffix": "da Anthropic — preciso em documentos jurídicos, médicos e técnicos complexos.", - "pricing.aiModels.premium.context": "200K tokens de contexto", - "pricing.aiModels.premium.precision": "Maior precisão", - "pricing.faq.title": "Perguntas frequentes", - "pricing.faq.q1": "Posso trocar de plano a qualquer momento?", - "pricing.faq.a1": "Sim. O upgrade é imediato e proporcional. O downgrade entra em vigor no final do período atual.", - "pricing.faq.q2": "O que é a «Tradução IA Essencial»?", - "pricing.faq.a2": "É nosso motor de IA. Ele compreende o contexto dos seus documentos, preserva a formatação e lida com termos técnicos muito melhor do que a tradução clássica.", - "pricing.faq.q3": "Qual a diferença entre IA Essencial e IA Premium?", - "pricing.faq.a3": "A IA Essencial usa um modelo otimizado (excelente custo-benefício). A IA Premium usa Claude 3.5 Haiku da Anthropic, mais precisa em documentos jurídicos, médicos e técnicos complexos.", - "pricing.faq.q4": "Meus documentos são mantidos após a tradução?", - "pricing.faq.a4": "Os arquivos traduzidos ficam disponíveis de acordo com seu plano (30 dias Starter, 90 dias Pro, 1 ano Business). São criptografados em repouso e em trânsito.", - "pricing.faq.q5": "O que acontece se eu exceder minha cota mensal?", - "pricing.faq.a5": "Você pode comprar créditos avulsos ou fazer upgrade do plano. Você será notificado ao atingir 80 % de uso.", - "pricing.faq.q6": "Existe um teste gratuito para os planos pagos?", - "pricing.faq.a6": "O plano Gratuito é permanente e não exige cartão. Para os planos Pro e Business, entre em contato para um teste de 14 dias.", - "pricing.faq.q7": "Quais formatos de arquivo são suportados?", - "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx) e em breve PDF. Todos os planos suportam os mesmos formatos.", - "pricing.cta.title": "Pronto para começar?", - "pricing.cta.subtitle": "Comece gratuitamente, sem cartão de crédito. Faça upgrade quando precisar.", - "pricing.cta.createAccount": "Criar uma conta gratuita", - "pricing.cta.login": "Entrar", - "pricing.toast.demo": "Modo demo — O Stripe ainda não está configurado. Em produção, você seria redirecionado para o pagamento para ativar o plano {planId}.", - "pricing.toast.networkError": "Erro de rede. Por favor, tente novamente.", - "pricing.toast.paymentError": "Erro ao criar o pagamento.", - "register.title": "Criar uma conta", - "register.subtitle": "Comece a traduzir gratuitamente", - "register.error.failed": "Falha no registro", - "register.name.label": "Nome", - "register.name.placeholder": "Seu nome", - "register.name.error": "O nome deve ter pelo menos 2 caracteres", - "register.email.label": "Endereço de e-mail", - "register.email.placeholder": "voce@exemplo.com", - "register.email.error": "Endereço de e-mail inválido", - "register.password.label": "Senha", - "register.password.error": "A senha deve ter pelo menos 8 caracteres, com uma letra maiúscula, uma minúscula e um dígito", - "register.password.show": "Mostrar senha", - "register.password.hide": "Ocultar senha", - "register.password.strengthLabel": "Força:", - "register.password.strength.weak": "Fraca", - "register.password.strength.medium": "Média", - "register.password.strength.strong": "Forte", - "register.confirmPassword.label": "Confirmar senha", - "register.confirmPassword.error": "As senhas não coincidem", - "register.confirmPassword.show": "Mostrar", - "register.confirmPassword.hide": "Ocultar", - "register.submit.creating": "Criando conta...", - "register.submit.create": "Criar minha conta", - "register.hasAccount": "Já tem uma conta?", - "register.login": "Entrar", - "register.terms.prefix": "Ao criar uma conta, você aceita nossos", - "register.terms.link": "termos de serviço", - "login.errorTitle": "Login Error", - "login.welcomeBack": "Welcome back", - "login.signInToContinue": "Sign in to continue translating", - "login.email": "Email", - "login.emailPlaceholder": "you@example.com", - "login.password": "Password", - "login.forgotPassword": "Forgot password?", - "login.passwordPlaceholder": "••••••••", - "login.signingIn": "Signing in...", - "login.signIn": "Sign In", - "login.noAccount": "Don't have an account?", - "login.signUpFree": "Sign up for free", - "login.orContinueWith": "ou continuar com e-mail", - "login.google.connecting": "A ligar…", - "login.google.errorGeneric": "Ocorreu um erro no início de sessão com Google.", - "login.google.errorFailed": "Falha no início de sessão com Google. Tente novamente.", - "forgotPassword.enterEmail": "Please enter your email address", - "forgotPassword.error": "An error occurred", - "forgotPassword.title": "Forgot Password", - "forgotPassword.checkEmail": "Check your inbox", - "forgotPassword.subtitle": "Enter your email to receive a reset link", - "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", - "forgotPassword.emailLabel": "Email address", - "forgotPassword.emailPlaceholder": "you@example.com", - "forgotPassword.sending": "Sending...", - "forgotPassword.sendLink": "Send reset link", - "forgotPassword.backToLogin": "Back to login", - "forgotPassword.loading": "Loading...", - "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", - "resetPassword.passwordMismatch": "Passwords do not match", - "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", - "resetPassword.error": "An error occurred", - "resetPassword.invalidLink": "Invalid link", - "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", - "resetPassword.requestNewLink": "Request new link", - "resetPassword.successTitle": "Password reset", - "resetPassword.newPasswordTitle": "New password", - "resetPassword.successSubtitle": "You will be redirected to login", - "resetPassword.subtitle": "Set your new password", - "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", - "resetPassword.newPassword": "New password", - "resetPassword.showPassword": "Show password", - "resetPassword.hidePassword": "Hide password", - "resetPassword.confirmPassword": "Confirm password", - "resetPassword.resetting": "Resetting...", - "resetPassword.resetPassword": "Reset password", - "resetPassword.backToLogin": "Back to login", - "resetPassword.loading": "Loading...", - "common.loading": "Carregando...", - "profile.header.title": "Meu perfil", - "profile.header.subtitle": "Gerencie sua conta e preferências.", - "profile.tabs.account": "Conta", - "profile.tabs.subscription": "Assinatura", - "profile.tabs.preferences": "Preferências", - "profile.account.user": "Usuário", - "profile.account.memberSince": "Membro desde", - "profile.plan.label": "Plano", - "profile.plan.free": "Gratuito", - "profile.plan.starter": "Starter", - "profile.plan.pro": "Pro", - "profile.plan.business": "Business", - "profile.plan.enterprise": "Enterprise", - "profile.plan.pricePerMonth": "{price} €/mês", - "profile.subscription.canceling": "Cancelando", - "profile.subscription.active": "Ativa", - "profile.subscription.unknown": "Desconhecido", - "profile.subscription.accessUntil": "Acesso até", - "profile.subscription.renewalOn": "Renovação em", - "profile.subscription.upgradePlan": "Atualizar para um plano pago", - "profile.subscription.changePlan": "Alterar plano", - "profile.subscription.manageBilling": "Gerenciar cobrança", - "profile.subscription.billingUnavailable": "Portal de cobrança indisponível.", - "profile.subscription.billingError": "Erro ao acessar o portal de cobrança.", - "profile.subscription.cancelSuccess": "Assinatura cancelada. Você mantém o acesso até o final do período.", - "profile.subscription.cancelError": "Erro durante o cancelamento.", - "profile.subscription.networkError": "Erro de rede.", - "profile.usage.title": "Uso este mês", - "profile.usage.resetOn": "Redefinição em", - "profile.usage.documents": "Documentos", - "profile.usage.pages": "Páginas", - "profile.usage.extraCredits": "crédito extra", - "profile.usage.extraCreditsPlural": "créditos extras", - "profile.usage.quotaReached": "Cota atingida", - "profile.usage.quotaReachedDesc": "Atualize para um plano superior para continuar.", - "profile.usage.unlockMore": "Desbloqueie mais traduções com um plano pago.", - "profile.usage.viewPlans": "Ver planos", - "profile.usage.includedInPlan": "Incluído no seu plano", - "profile.danger.title": "Zona de perigo", - "profile.danger.description": "O cancelamento entra em vigor no final do seu período atual. Você mantém o acesso até essa data.", - "profile.danger.confirm": "Tem certeza? Esta ação não pode ser desfeita.", - "profile.danger.confirmCancel": "Confirmar cancelamento", - "profile.danger.cancelSubscription": "Cancelar minha assinatura", - "profile.danger.keep": "Não, manter", - "profile.prefs.interfaceLang": "Idioma da interface", - "profile.prefs.interfaceLangDesc": "O idioma é detectado automaticamente com base no seu navegador. Você pode alterá-lo manualmente.", - "profile.prefs.defaultTargetLang": "Idioma de destino padrão", - "profile.prefs.selectLanguage": "Selecione um idioma", - "profile.prefs.defaultTargetLangDesc": "Este idioma será pré-selecionado para suas traduções.", - "profile.prefs.save": "Salvar", - "profile.prefs.theme": "Tema", - "profile.prefs.themeDesc": "Escolha a aparência da interface", - "profile.prefs.cache": "Cache", - "profile.prefs.cacheDesc": "Limpar o cache local pode corrigir alguns problemas de exibição.", - "profile.prefs.clearing": "Limpando...", - "profile.prefs.clearCache": "Limpar cache", - "settings.title": "Configurações", - "settings.subtitle": "Configuração geral do aplicativo", - "settings.formats.title": "Formatos suportados", - "settings.formats.subtitle": "Tipos de documentos que você pode traduzir", - "settings.formats.formulas": "Fórmulas", - "settings.formats.styles": "Estilos", - "settings.formats.images": "Imagens", - "settings.formats.headers": "Cabeçalhos", - "settings.formats.tables": "Tabelas", - "settings.formats.slides": "Slides", - "settings.formats.notes": "Notas", - "settings.cache.title": "Cache", - "settings.cache.desc": "Limpar o cache local pode corrigir alguns problemas de exibição.", - "settings.cache.clearing": "Limpando...", - "settings.cache.clear": "Limpar cache", - "services.title": "Provedores de tradução", - "services.subtitle": "Os provedores são configurados pelo administrador. Você pode ver quais estão disponíveis para sua conta.", - "services.loading": "Carregando provedores...", - "services.noProviders": "Nenhum provedor está configurado no momento. Entre em contato com seu administrador.", - "services.classic": "Tradução clássica", - "services.llmPro": "LLM · Contextual (Pro)", - "services.available": "Disponível", - "services.model": "Modelo", - "services.adminOnly.title": "A configuração de provedores é exclusiva do administrador", - "services.adminOnly.desc": "Chaves de API, seleção de modelos e ativação de provedores são gerenciadas exclusivamente pelo administrador no painel administrativo. Você nunca precisa inserir uma chave de API.", - "apiKeys.title": "Chaves de API", - "apiKeys.subtitle": "Gerencie suas chaves de API para acesso programático à API de tradução.", - "apiKeys.loading": "Carregando...", - "apiKeys.sectionTitle": "API e automação", - "apiKeys.sectionDesc": "Gere e gerencie suas chaves de API para fluxos de automação", - "apiKeys.keysUsed": "{total} de {max} chaves usadas", - "apiKeys.maxReached": "Máximo de chaves atingido. Revogue uma chave para gerar uma nova.", - "apiKeys.canGenerate": "Você pode gerar mais {count} chave", - "apiKeys.canGeneratePlural": "Você pode gerar mais {count} chaves", - "apiKeys.generateNew": "Gerar nova chave", - "apiKeys.keyRevoked": "Chave revogada", - "apiKeys.keyRevokedDesc": "A chave de API foi revogada com sucesso.", - "apiKeys.keyNotFound": "Chave não encontrada", - "apiKeys.keyNotFoundDesc": "A chave de API não existe mais. Ela pode ter sido revogada anteriormente.", - "apiKeys.error": "Erro", - "apiKeys.revokeError": "Falha ao revogar a chave de API. Tente novamente.", - "apiKeys.limitReached": "Limite atingido", - "apiKeys.limitReachedDesc": "Você atingiu o máximo de 10 chaves de API. Revogue uma chave existente para gerar uma nova.", - "apiKeys.proRequired": "Recurso Pro necessário", - "apiKeys.proRequiredDesc": "Chaves de API são um recurso Pro. Atualize sua conta.", - "apiKeys.generateError": "Falha ao gerar a chave de API. Tente novamente.", - "apiKeys.upgrade.title": "Chaves de API", - "apiKeys.upgrade.subtitle": "Automatize suas traduções com acesso à API", - "apiKeys.upgrade.feat1": "Gere chaves de API ilimitadas", - "apiKeys.upgrade.feat2": "Automatize a tradução de documentos", - "apiKeys.upgrade.feat3": "Notificações por webhook", - "apiKeys.upgrade.feat4": "Modos de tradução LLM", - "apiKeys.upgrade.proFeature": "Chaves de API são um recurso {pro}. Atualize para desbloquear a automação por API.", - "apiKeys.upgrade.pro": "Pro", - "apiKeys.upgrade.cta": "Atualizar para Pro", - "apiKeys.dialog.maxTitle": "Máximo de chaves atingido", - "apiKeys.dialog.maxDesc": "Você atingiu o máximo de 10 chaves de API. Revogue uma chave existente antes de gerar uma nova.", - "apiKeys.dialog.close": "Fechar", - "apiKeys.dialog.generated": "Chave de API gerada!", - "apiKeys.dialog.generatedDesc": "Sua nova chave de API foi criada. Copie-a agora — ela não será exibida novamente.", - "apiKeys.dialog.important": "Importante:", - "apiKeys.dialog.importantDesc": "Esta é a única vez que você verá esta chave. Armazene-a com segurança.", - "apiKeys.dialog.apiKey": "Chave de API", - "apiKeys.dialog.name": "Nome:", - "apiKeys.dialog.done": "Concluído", - "apiKeys.dialog.copied": "Já copiei a chave", - "apiKeys.dialog.generateTitle": "Gerar nova chave de API", - "apiKeys.dialog.generateDesc": "Crie uma nova chave de API para acesso programático à API de tradução.", - "apiKeys.dialog.keyName": "Nome da chave (opcional)", - "apiKeys.dialog.keyNamePlaceholder": "ex., Produção, Staging", - "apiKeys.dialog.keyNameHint": "Um nome descritivo para identificar esta chave posteriormente.", - "apiKeys.dialog.nameTooLong": "O nome deve ter {max} caracteres ou menos", - "apiKeys.dialog.nameInvalid": "O nome só pode conter letras, números, espaços, hifens e sublinhados", - "apiKeys.dialog.cancel": "Cancelar", - "apiKeys.dialog.generating": "Gerando...", - "apiKeys.dialog.generate": "Gerar chave", - "apiKeys.table.name": "Nome", - "apiKeys.table.prefix": "Prefixo", - "apiKeys.table.created": "Criada", - "apiKeys.table.lastUsed": "Último uso", - "apiKeys.table.never": "Nunca", - "apiKeys.table.actions": "Ações", - "apiKeys.table.revoke": "Revogar", - "apiKeys.table.copyPrefix": "Copiar prefixo da chave", - "apiKeys.table.revokeKey": "Revogar chave", - "apiKeys.revokeDialog.title": "Revogar chave de API", - "apiKeys.revokeDialog.desc": "Tem certeza de que deseja revogar a chave \"{name}\"? Esta ação não pode ser desfeita.", - "apiKeys.revokeDialog.confirm": "Sim, revogar", - "apiKeys.revokeDialog.cancel": "Cancelar", - "context.proTitle": "Recurso Pro", - "context.proDesc": "Contexto e glossários profissionais estão disponíveis nos planos Pro, Business e Enterprise. Eles fornecem traduções mais precisas através de instruções e vocabulário específico do seu domínio.", - "context.viewPlans": "Ver planos", - "context.title": "Contexto e glossário", - "context.subtitle": "Melhore a qualidade da tradução com instruções e vocabulário específico do seu domínio.", - "context.presets.title": "Glossários profissionais", - "context.presets.desc": "Carregue um glossário completo com instruções e terminologia especializada", - "context.instructions.title": "Instruções de contexto", - "context.instructions.desc": "Instruções que a IA seguirá durante a tradução", - "context.instructions.placeholder": "Ex.: Você traduz documentos técnicos de climatização. Use terminologia de engenharia precisa...", - "context.glossary.title": "Glossário técnico", - "context.glossary.desc": "Formato: origem=destino (um por linha). Glossários carregados via predefinição são editáveis.", - "context.glossary.terms": "termos no glossário", - "context.clearAll": "Limpar tudo", - "context.saving": "Salvando...", - "context.save": "Salvar", - "translate.glossary.title": "Glossário", - "translate.glossary.select": "Selecionar glossário", - "translate.glossary.none": "Nenhum", - "translate.glossary.terms": "termos", - "translate.glossary.proOnly": "Atualize para Pro para usar glossários", - "translate.glossary.myGlossaries": "Meus glossários", - "translate.glossary.fromTemplate": "Criar do modelo", - "translate.glossary.noGlossaryForPair": "Sem glossário para", - "translate.glossary.noGlossaries": "Sem glossários", - "translate.glossary.loading": "Carregando...", - "translate.glossary.classicMode": "Motor neutro sem glossário (apenas IA)", - "translate.glossary.selectPlaceholder": "Selecionar um glossário...", - "translate.glossary.multilingual": "MULTILÍNGUE", - "translate.glossary.noGlossaryAvailable": "Nenhum glossário disponível", - "translate.glossary.filterByLang": "Filtrar por idioma", - "translate.glossary.active": "Ativo", - "translate.glossary.inactive": "Inativo", - "translate.glossary.availableTemplates": "Modelos disponíveis", - "translate.glossary.importing": "Importando...", - "translate.glossary.imported": "(Importado)", - "translate.glossary.noGlossaryForSource": "Nenhum glossário ou modelo para o idioma de origem", - "translate.glossary.createGlossary": "Criar um glossário", - "translate.glossary.showAll": "Mostrar todos os glossários", - "translate.glossary.activePreview": "Pré-visualização de correspondências ativas:", - "translate.glossary.total": "no total", - "translate.glossary.moreTerms": "termos adicionais", - "translate.glossary.noTerms": "Nenhum termo neste glossário.", - "translate.glossary.sourceTerm": "Termo de origem", - "translate.glossary.translation": "Tradução", - "translate.glossary.addTerm": "Adicionar termo", - "translate.glossary.disabledMode": "Motor neutro sem glossário aplicado", - "translate.glossary.addTermError": "Erro ao adicionar o termo", - "translate.glossary.networkError": "Erro de rede", - "translate.glossary.importFailed": "Falha na importação ({status})", - "translate.glossary.helpText": "O glossário força a tradução precisa de termos. Escolha um glossário cujo idioma de origem corresponda ao idioma original do seu documento.", - "translate.glossary.sourceWarning": "Atenção: Este glossário usa o idioma de origem", - "translate.glossary.sourceWarningBut": "mas o seu documento está configurado em", - "translate.glossary.targetWarning": "Incompatibilidade de destino: Este glossário foi projetado para traduzir para", - "translate.glossary.targetWarningBut": "mas o seu documento tem como destino", - "translate.glossary.targetWarningEnd": "Os termos podem não ser relevantes.", - "context.presets.createGlossary": "Criar glossário", - "context.presets.created": "Glossário criado", - "context.presets.createdDesc": "O glossário \"{name}\" foi criado com {count} termos.", - "context.presets.hint": "Clique em um preset para criar um glossário com termos específicos do domínio. Gerencie seus glossários na seção Glossários.", - "context.glossary.manage": "Gerenciar glossários", - "context.saved": "Salvo", - "context.savedDesc": "Suas instruções de contexto foram salvas.", - "admin.login.title": "Administração", - "admin.login.required": "Login necessário", - "admin.login.password": "Senha de administrador", - "admin.login.connecting": "Conectando...", - "admin.login.access": "Acessar painel admin", - "admin.login.restricted": "Restrito a administradores", - "admin.layout.checking": "Verificando autenticação...", - "admin.dashboard.title": "Painel de Administração", - "admin.dashboard.subtitle": "Painel de controle do administrador", - "admin.dashboard.refresh": "Atualizar", - "admin.dashboard.refreshTooltip": "Atualizar dados do painel", - "admin.dashboard.config": "Configuração do sistema", - "admin.dashboard.maxFileSize": "Tamanho máximo do arquivo:", - "admin.dashboard.translationService": "Serviço de tradução:", - "admin.dashboard.formats": "Formatos:", - "admin.nav.dashboard": "Dashboard", - "admin.nav.users": "Usuários", - "admin.nav.pricing": "Preços e Stripe", - "admin.nav.providers": "Provedores", - "admin.nav.system": "Sistema", - "admin.nav.logs": "Registros", - "admin.users.title": "Gestão de Usuários", - "admin.users.subtitle": "Visualizar e gerenciar contas de usuários", - "admin.users.planUpdated": "Plano atualizado", - "admin.users.planChanged": "O plano foi alterado para \"{plan}\" com sucesso.", - "admin.users.unknownError": "Erro desconhecido", - "admin.users.error": "Erro", - "admin.users.planUpdateError": "Não foi possível atualizar o plano: {message}", - "admin.users.noKeys": "Sem chaves", - "admin.users.noKeysDesc": "Este usuário não tem chaves API ativas.", - "admin.users.keysRevoked": "Chaves revogadas", - "admin.users.keysRevokedDesc": "{count} chave(s) API revogada(s) com sucesso.", - "admin.users.revokeError": "Não foi possível revogar as chaves: {message}", - "admin.users.retry": "Tentar novamente", - "admin.system.title": "Sistema", - "admin.system.subtitle": "Monitorar o status do sistema e gerenciar recursos", - "admin.system.quotas": "Cotas de tradução", - "admin.system.resetQuotas": "Redefinir cotas mensais", - "admin.system.resetting": "Redefinindo...", - "admin.system.reset": "Redefinir", - "admin.system.allOperational": "Todos os sistemas operacionais", - "admin.system.issuesDetected": "Problemas no sistema detectados", - "admin.system.waitingData": "Aguardando dados...", - "admin.system.purging": "Limpando...", - "admin.system.clean": "Limpar", - "admin.system.purge": "Limpar", - "memento.title": "Descubra o Momento", - "memento.slogan": "O Momento é mais do que uma aplicação de notas. É um ecossistema inteligente que conecta, analisa e desenvolve suas ideias em tempo real usando 6 agentes de IA e busca semântica avançada.", - "memento.ctaFree": "Começar grátis", - "memento.ctaMore": "Saiba mais", - "common.backToHome": "Voltar ao início", - "dashboard.topbar.interfaceLabel": "Interface de tradução", - "dashboard.topbar.premiumAccess": "Acesso Premium", - "landing.hero.contextEngine": "Tradução detectada: Termo técnico de manutenção para sistemas HVAC...", - "landing.hero.liveAnalysis": "Análise em tempo real", - "landing.hero.termsDetected": "termos detectados", - "landing.steps.process": "PROCESSO", - "landing.translate.newProject": "Novo projeto", - "landing.translate.title": "Traduzir um documento", - "landing.translate.subtitle": "Importe um arquivo e escolha o idioma de destino", - "landing.translate.sourceDocument": "Documento fonte", - "landing.translate.configuration": "Configuração", - "landing.translate.sourceLang": "Idioma de origem", - "landing.translate.targetLang": "Idioma de destino", - "landing.translate.provider": "Fornecedor", - "landing.translate.startTranslation": "Iniciar tradução", - "landing.translate.zeroRetention": "Retenção zero", - "landing.translate.filesDeleted": "Ficheiros eliminados após processamento", - "landing.translate.dropHere": "Arraste e solte aqui", - "landing.translate.supportedFormats": "Ficheiros DOCX, XLSX, PPTX ou PDF suportados", - "landing.translate.aiAnalysis": "Análise IA Ativa", - "landing.translate.processing": "Em processamento", - "landing.translate.preservingLayout": "O seu layout está a ser preservado", - "layout.nav.apiAccess": "Acesso à API", - "layout.footer.terms": "Termos", - "layout.footer.privacy": "Privacidade", - "fileUploader.uploadDocument": "Carregar documento", - "fileUploader.uploadDesc": "Arraste e solte ou clique para selecionar um ficheiro (Excel, Word, PowerPoint)", - "fileUploader.dropHere": "Solte o ficheiro aqui…", - "fileUploader.dragAndDrop": "Arraste e solte o documento aqui", - "fileUploader.orClickBrowse": "ou clique para procurar", - "fileUploader.preview": "Pré-visualização", - "fileUploader.translationOptions": "Opções de tradução", - "fileUploader.configureSettings": "Configure as suas definições de tradução", - "fileUploader.targetLanguage": "Idioma de destino", - "fileUploader.selectLanguage": "Selecionar idioma", - "fileUploader.translationProvider": "Provedor de tradução", - "fileUploader.selectProvider": "Selecionar fornecedor", - "fileUploader.advancedOptions": "Opções avançadas", - "fileUploader.translateImages": "Traduzir imagens", - "fileUploader.translating": "A traduzir…", - "fileUploader.translateDocument": "Traduzir documento", - "fileUploader.processing": "A processar…", - "fileUploader.translationError": "Erro de tradução", - "fileUploader.translationComplete": "Tradução concluída!", - "fileUploader.translationCompleteDesc": "O seu documento foi traduzido com sucesso mantendo toda a formatação.", - "fileUploader.download": "Baixar documento traduzido", - "fileUploader.webgpuUnsupported": "WebGPU não é suportado neste navegador. Use Chrome 113+ ou Edge 113+.", - "fileUploader.webllmNotLoaded": "Modelo WebLLM não carregado. Vá a Definições > Serviços de tradução para carregar um modelo.", - "fileUploader.extracting": "A extrair textos do documento…", - "fileUploader.noTranslatable": "Nenhum texto traduzível encontrado no documento", - "fileUploader.foundTexts": "Encontrados {count} textos para traduzir", - "fileUploader.translatingItem": "A traduzir {current}/{total}: «{preview}»", - "fileUploader.reconstructing": "A reconstruir o documento…", - "fileUploader.translatingLocally": "A traduzir localmente com WebLLM…", - "checkout.activating": "A ativar…", - "checkout.activatingDesc": "Estamos a atualizar a sua assinatura, aguarde.", - "checkout.paymentConfirmed": "Pagamento confirmado!", - "checkout.subscriptionActivated": "Assinatura ativada!", - "checkout.planActivated": "Plano {plan} ativado!", - "checkout.redirectingToProfile": "A redirecionar para o seu perfil…", - "checkout.paymentReceived": "Pagamento recebido", - "checkout.redirecting": "A redirecionar…", - "checkout.syncError": "Erro de sincronização", - "checkout.networkError": "Erro de rede. O seu pagamento está confirmado — recarregue o seu perfil.", - "dashboard.checkoutSyncError": "Erro ao sincronizar o pagamento.", - "dashboard.networkRefresh": "Erro de rede. Atualize a página.", - "dashboard.continueToTranslate": "Continuar para a tradução", - "langSelector.search": "Pesquisar…", - "langSelector.noResults": "Sem resultados", - "langSelector.source": "Origem", - "langSelector.target": "Destino", - "langSelector.swap": "Trocar", - "translateComplete.highQuality": "Alta qualidade", - "translateComplete.segments": "Segmentos", - "translateComplete.characters": "Caracteres", - "translateComplete.confidence": "Confiança", - "providerTheme.deepseek.badge": "Essencial", - "providerTheme.deepseek.subBadge": "Técnico e económico", - "providerTheme.deepseek.desc": "Tradução ultra-precisa e económica, ideal para documentos técnicos e código.", - "providerTheme.openai.badge": "Premium", - "providerTheme.openai.subBadge": "Alta fidelidade", - "providerTheme.openai.desc": "O padrão global de IA. Máxima consistência textual e respeito estrito do estilo.", - "providerTheme.minimax.badge": "Avançada", - "providerTheme.minimax.subBadge": "Desempenho", - "providerTheme.minimax.desc": "Velocidade de execução incrível e excelente compreensão de estruturas complexas.", - "providerTheme.openrouter.badge": "Expresso", - "providerTheme.openrouter.subBadge": "Multi-modelo", - "providerTheme.openrouter.desc": "Acesso unificado aos melhores modelos open-source otimizados para tradução.", - "providerTheme.openrouter_premium.badge": "Ultra", - "providerTheme.openrouter_premium.subBadge": "Contexto máximo", - "providerTheme.openrouter_premium.desc": "Assistido pelos modelos mais avançados (GPT-4o, Claude Sonnet 4.6) para documentos longos.", - "providerTheme.zai.badge": "Especializada", - "providerTheme.zai.subBadge": "Finanças e Direito", - "providerTheme.zai.desc": "Modelo afinado para terminologias empresariais exigentes (jurídico, financeiro).", - "providerTheme.default.badge": "Moderno", - "providerTheme.default.subBadge": "Raciocínio IA", - "providerTheme.default.desc": "Tradução por modelo de linguagem grande (LLM) com análise semântica avançada.", - "providerTheme.classic.google.label": "Google Tradutor", - "providerTheme.classic.google.desc": "Tradução ultra-rápida cobrindo mais de 130 idiomas. Recomendado para fluxos gerais.", - "providerTheme.classic.deepl.label": "DeepL Pro", - "providerTheme.classic.deepl.desc": "Tradução de alta precisão conhecida pela sua fluência e formulações naturais.", - "providerTheme.classic.google_cloud.label": "Google Cloud API", - "providerTheme.classic.google_cloud.desc": "Motor cloud profissional otimizado para processar grandes volumes de documentos.", - "providerSelector.noClassic": "Nenhum tradutor padrão disponível.", - "providerSelector.noLlm": "Nenhum modelo de IA configurado.", - "providerSelector.costOne": "Custo: 1 crédito por página", - "providerSelector.costFive": "Custo: 5 créditos por página (Fator Premium)", - "providerSelector.unlockContextual": "Desbloqueie a tradução contextual premium para os seus documentos completos.", - "translate.header.processing": "Processamento em curso", - "translate.header.aiActive": "Análise IA ativa", - "translate.header.aiActiveDesc": "O seu layout está a ser preservado pelo nosso motor contextual.", - "translate.header.completed": "Concluído", - "translate.header.completedTitle": "Tradução concluída", - "translate.header.proSpace": "Espaço Pro", - "translate.header.translateDoc": "Traduzir um documento", - "translate.header.translateDocDesc": "Mantenha o layout original com o nosso motor de tradução de ultra-alta fidelidade.", - "translate.upload.nativeFormat": "Formato nativo", - "translate.fileType.word": "Word (.docx)", - "translate.fileType.excel": "Excel (.xlsx)", - "translate.fileType.slides": "Slides (.pptx)", - "translate.fileType.pdf": "PDF (.pdf)", - "translate.startTranslation": "Iniciar tradução", - "translate.submit": "A enviar…", - "translate.chooseTargetLang": "Por favor, escolha um idioma de destino", - "translate.pleaseLoadFile": "Por favor, carregue um ficheiro primeiro", - "translate.contextEngineActive": "Motor contextual ativo", - "translate.phase1": "Fase 1: Inicialização", - "translate.phase2": "Fase 2: Reconstrução contextual", - "translate.stat.segments": "segmentos", - "translate.stat.precision": "precisão", - "translate.stat.speedLabel": "velocidade", - "translate.stat.turbo": "Turbo", - "translate.stat.time": "tempo", - "translate.complete.masterQuality": "✓ Qualidade mestre", - "translate.download": "Baixar", - "translate.newTranslation": "+ Nova tradução", - "translate.failedTitle": "Erro de tradução", - "translate.retry": "Tentar novamente", - "translate.uploadAnother": "Carregar outro ficheiro", - "translate.monitor": "Monitor IA", - "translate.summary": "Resumo", - "translate.cancelProcess": "⟳ Cancelar o processo", - "translate.layoutIntegrity": "Integridade do layout", - "translate.secureHundred": "100% SEGURO", - "translate.okHundred": "100% OK", - "translate.preserveLayout": "Manter layout", - "translate.preserveLayoutDesc": "Manter o layout", - "translate.textOnly": "Apenas texto", - "translate.textOnlyDesc": "Tradução rápida apenas do texto", - "translate.unavailableStandard": "Indisponível no modo Padrão (apenas IA)", - "apiKeys.noKeysGenerated": "Nenhuma chave gerada", - "apiKeys.copied": "Copiado!", - "services.fallback.google.label": "Google Tradutor", - "services.fallback.google.desc": "Tradução rápida, mais de 130 idiomas", - "settings.formats.excel.name": "Excel", - "settings.formats.word.name": "Word", - "settings.formats.powerpoint.name": "PowerPoint", - "pricing.dashboard": "Painel", - "pricing.okSymbol": "✓", - "pricing.errSymbol": "✕", - }, - // ═══════════════════════════════════════════════════════════════ - // ITALIAN (it) - // ═══════════════════════════════════════════════════════════════ - it: { - "auth.brandName": "Wordly", - "dashboard.nav.translate": "Traduci", - "dashboard.nav.profile": "Il mio profilo", - "dashboard.nav.settings": "Impostazioni", - "dashboard.nav.context": "Contesto", - "dashboard.nav.services": "Servizi", - "dashboard.nav.apiKeys": "Chiavi API", - "dashboard.nav.glossaries": "Glossari", - "dashboard.header.title": "Dashboard", - "dashboard.header.subtitle": "Gestisci le tue traduzioni", - "dashboard.header.toggleMenu": "Menu", - "dashboard.header.profileTitle": "Il mio profilo", - "dashboard.sidebar.theme": "Tema", - "dashboard.sidebar.signOut": "Esci", - "dashboard.sidebar.backHome": "Torna alla home", - "dashboard.sidebar.upgradeToPro": "Passa a Pro →", - "cookieConsent.title": "Cookie su Wordly", - "cookieConsent.description": "Utilizziamo cookie essenziali per il funzionamento del servizio (sessione, sicurezza, lingua). Con il vostro consenso, utilizziamo anche cookie opzionali per misurare il traffico e migliorare il prodotto.", - "cookieConsent.acceptAll": "Accetta tutti", - "cookieConsent.essentialOnly": "Solo essenziali", - "cookieConsent.learnMore": "Scopri di più", - "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.", - "dashboard.translate.pageTitle": "Traduci un documento", - "dashboard.translate.pageSubtitle": "Importa un file e scegli la lingua di destinazione", - "dashboard.translate.errorNotificationTitle": "Errore", - "dashboard.translate.dropzone.uploadAria": "Area di rilascio file", - "dashboard.translate.dropzone.title": "Trascina qui il tuo file", - "dashboard.translate.dropzone.subtitle": "oppure clicca per selezionare (DOCX, XLSX, PPTX, PDF)", - "dashboard.translate.dropzone.replaceFile": "Sostituisci file", - "dashboard.translate.language.source": "Lingua di origine", - "dashboard.translate.language.target": "Lingua di destinazione", - "dashboard.translate.language.loading": "Caricamento lingue…", - "dashboard.translate.language.autoDetect": "Rilevamento automatico", - "dashboard.translate.language.selectPlaceholder": "Seleziona…", - "dashboard.translate.language.loadErrorPrefix": "Errore nel caricamento delle lingue", - "dashboard.translate.provider.loading": "Caricamento provider…", - "dashboard.translate.provider.noneConfigured": "Nessun provider configurato", - "dashboard.translate.provider.modelTitle": "Modello", - "dashboard.translate.provider.sectionTitle": "Provider", - "dashboard.translate.provider.llmDivider": "IA · Contestuale", - "dashboard.translate.provider.llmDividerPro": "IA · Contestuale (Pro)", - "dashboard.translate.provider.upgrade": "Passa a Pro", - "dashboard.translate.provider.upgradeSuffix": "per sbloccare la traduzione IA", - "dashboard.translate.trust.zeroRetention": "Zero conservazione", - "dashboard.translate.trust.deletedAfter": "File eliminati dopo l'elaborazione", - "dashboard.translate.actions.uploading": "Caricamento…", - "dashboard.translate.actions.translate": "Traduci", - "dashboard.translate.actions.filePrefix": "File: ", - "dashboard.translate.actions.cancel": "Annulla", - "dashboard.translate.actions.tryAgain": "Riprova", - "dashboard.translate.steps.uploading": "Caricamento file…", - "dashboard.translate.steps.starting": "Avvio traduzione…", - "dashboard.translate.complete.title": "Traduzione completata!", - "dashboard.translate.complete.descNamed": "Il tuo file {name} è stato tradotto correttamente.", - "dashboard.translate.complete.descGeneric": "Il tuo file è stato tradotto correttamente.", - "dashboard.translate.complete.downloading": "Download in corso…", - "dashboard.translate.complete.download": "Scarica", - "dashboard.translate.complete.newTranslation": "Nuova traduzione", - "dashboard.translate.complete.toastOkTitle": "Operazione riuscita", - "dashboard.translate.complete.toastOkDesc": "{name} è stato scaricato con successo.", - "dashboard.translate.complete.toastFailTitle": "Non riuscito", - "dashboard.translate.complete.toastFailDesc": "Traduzione non riuscita. Riprova.", - "dashboard.translate.sourceDocument": "Documento sorgente", - "dashboard.translate.configuration": "Configurazione", - "dashboard.translate.translating": "Traduzione in corso", - "dashboard.translate.liveMonitor": "Monitoraggio live", - "dashboard.translate.summary": "Riepilogo", - "dashboard.translate.engine": "Motore", - "dashboard.translate.confidence": "Confidenza", - "dashboard.translate.cancel": "Annulla", - "dashboard.translate.segments": "Segmenti", - "dashboard.translate.characters": "Caratteri", - "dashboard.translate.elapsed": "Trascorso", - "dashboard.translate.segPerMin": "Seg/min", - "dashboard.translate.highQuality": "Alta qualità", - "dashboard.translate.quality": "Qualità", - "dashboard.translate.completed": "Traduzione completata", - "dashboard.translate.replace": "Sostituisci", - "dashboard.translate.pdfMode.title": "Modalità traduzione PDF", - "dashboard.translate.pdfMode.preserveLayout": "Preserva layout", - "dashboard.translate.pdfMode.textOnly": "Solo testo", - "dashboard.translate.pdfMode.preserveLayoutDesc": "Mantiene immagini, tabelle e formattazione. Ideale per PDF semplici.", - "dashboard.translate.pdfMode.textOnlyDesc": "Traduce tutto il testo perfettamente. Output pulito, senza problemi di layout.", - "dashboard.translate.pipeline.upload": "Carica", - "dashboard.translate.pipeline.analyze": "Analizza", - "dashboard.translate.pipeline.translate": "Traduzione", - "dashboard.translate.pipeline.rebuild": "Ricostruisci", - "dashboard.translate.pipeline.finalize": "Finalizza", - "dashboard.translate.progress.processingFallback": "Elaborazione…", - "dashboard.translate.progress.connectionLost": "Connessione persa. Riprovo…", - "dashboard.translate.progress.failedTitle": "Traduzione fallita", - "dashboard.translate.error.unexpected": "Si è verificato un errore imprevisto. Riprova.", - "dashboard.translate.error.noResult": "La traduzione non ha prodotto risultati. Verifica che il documento contenga testo, quindi riprova o scegli un altro motore.", - "dashboard.translate.error.apiKey": "Chiave API non valida o mancante. Contatta l'amministratore per configurare le chiavi.", - "dashboard.translate.error.quota": "Limite di utilizzo raggiunto. Riprova tra qualche minuto o scegli un altro motore.", - "dashboard.translate.error.timeout": "Connessione al servizio di traduzione scaduta. Controlla la rete e riprova.", - "dashboard.translate.error.sessionExpired": "Sessione scaduta. Clicca su Riprova per riavviare la traduzione.", - "dashboard.translate.error.empty": "Il documento sembra vuoto o non contiene testo traducibile (PDF scansionato?).", - "dashboard.translate.error.unsupported": "Formato file non supportato o file danneggiato.", - "dashboard.translate.error.connection": "Connessione persa. Controlla la rete e riprova.", - "dashboard.translate.error.generic": "Traduzione fallita: {detail}", - "dashboard.translate.error.title": "Traduzione fallita", - "dashboard.translate.retry": "Riprova traduzione", - "dashboard.translate.newFile": "Nuovo file", - "dashboard.translate.modeAI": "Modalità IA", - "dashboard.translate.modeClassic": "Modalità Classica", - "dashboard.translate.glossaryLLMHint": "Glossari disponibili in modalità IA", - "dashboard.translate.submitting": "Invio in corso...", - "dashboard.translate.submit": "Avvia traduzione", - "dashboard.translate.noFile": "Carica prima un file", - "dashboard.translate.noTargetLang": "Seleziona una lingua di destinazione", - "glossaries.yourGlossaries": "I tuoi glossari", - "glossaries.title": "Glossari e Contesto", - "glossaries.description": "Gestisci i tuoi glossari e le istruzioni di contesto per traduzioni più precise.", - "glossaries.createNew": "Crea nuovo", - "glossaries.empty": "Nessun glossario", - "glossaries.emptyDesc": "Crea il tuo primo glossario o carica un preset professionale sopra", - "glossaries.defineTerms": "termini", - "glossaries.aboutTitle": "Informazioni sui glossari", - "glossaries.aboutDesc": "I glossari ti permettono di definire traduzioni esatte per termini specifici. Durante la traduzione, i termini del glossario garantiscono traduzioni coerenti e precise.", - "glossaries.aboutFormat": "Ogni termine ha una parola sorgente e traduzioni in più lingue. Seleziona un glossario nella pagina di traduzione per applicarlo.", - "glossaries.toast.created": "Glossario creato", - "glossaries.toast.createdDesc": "Il glossario \"{name}\" è stato creato.", - "glossaries.toast.imported": "Glossario importato", - "glossaries.toast.importedDesc": "Il glossario \"{name}\" è stato importato.", - "glossaries.toast.updated": "Glossario aggiornato", - "glossaries.toast.updatedDesc": "Il glossario \"{name}\" è stato aggiornato.", - "glossaries.toast.deleted": "Glossario eliminato", - "glossaries.toast.deletedDesc": "Il glossario è stato eliminato.", - "glossaries.toast.error": "Errore", - "glossaries.toast.errorCreate": "Impossibile creare il glossario", - "glossaries.toast.errorImport": "Impossibile importare il glossario", - "glossaries.toast.errorUpdate": "Impossibile aggiornare il glossario", - "glossaries.toast.errorDelete": "Impossibile eliminare il glossario", - "glossaries.dialog.title": "Nuovo glossario", - "glossaries.dialog.description": "Crea un glossario per le tue traduzioni", - "glossaries.dialog.nameLabel": "Nome", - "glossaries.dialog.namePlaceholder": "Il mio glossario", - "glossaries.dialog.tabTemplates": "Modelli", - "glossaries.dialog.tabFile": "File", - "glossaries.dialog.tabManual": "Manuale", - "glossaries.dialog.cancel": "Annulla", - "glossaries.dialog.creating": "Creazione…", - "glossaries.dialog.importing": "Importazione…", - "glossaries.dialog.importBtn": "Importa", - "glossaries.dialog.selectPrompt": "Seleziona", - "glossaries.dialog.createBtn": "Crea", - "glossaries.dialog.createEmpty": "Crea vuoto", - "glossaries.dialog.terms": "termini", - "glossaries.dialog.templatesDesc": "Scegli un modello predefinito", - "glossaries.dialog.templatesEmpty": "Nessun modello disponibile", - "glossaries.dialog.dropTitle": "Trascina qui un file CSV", - "glossaries.dialog.dropOr": "oppure", - "glossaries.dialog.dropFormats": "CSV, TSV, TXT", - "glossaries.termEditor.addTerm": "Aggiungi termine", - "glossaries.termEditor.maxReached": "Raggiunto il massimo di {max} termini per glossario.", - "glossaries.dialog.formatTitle": "Formato", - "glossaries.dialog.formatDesc": "origine,destinazione (uno per riga)", - "glossaries.dialog.formatNote": "La prima riga viene saltata se rilevata come intestazione", - "glossaries.dialog.errorFormat": "Formato non supportato", - "glossaries.dialog.errorSize": "File troppo grande", - "glossaries.dialog.errorEmpty": "File vuoto", - "glossaries.dialog.errorRead": "Errore di lettura", - "glossaries.dialog.parsing": "Analisi…", - "glossaries.dialog.termsImported": "termini importati", - "glossaries.dialog.changeFile": "Cambia file", - "glossaries.dialog.retry": "Riprova", - "glossaries.edit.title": "Modifier le glossaire", - "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", - "glossaries.edit.nameLabel": "Nom du glossaire", - "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", - "glossaries.edit.sourceLang": "Langue source", - "glossaries.edit.targetLang": "Langue cible", - "glossaries.edit.termsLabel": "Termes ({count} valides)", - "glossaries.edit.exportCsv": "Exporter CSV", - "glossaries.edit.importCsv": "Importer CSV", - "glossaries.edit.cancel": "Annuler", - "glossaries.edit.saving": "Enregistrement...", - "glossaries.edit.saveChanges": "Enregistrer les modifications", - "glossaries.edit.importFailedTitle": "Échec de l'importation", - "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", - "glossaries.edit.importSuccessTitle": "Importation réussie", - "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", - "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", - "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", - "glossaries.delete.title": "Supprimer le glossaire", - "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", - "glossaries.delete.warning": "Cette action est irréversible", - "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", - "glossaries.delete.cancel": "Annuler", - "glossaries.delete.deleting": "Suppression...", - "glossaries.delete.deleteBtn": "Supprimer", - "glossaries.upgrade.title": "Glossaires", - "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", - "glossaries.upgrade.feature1": "Créez plusieurs glossaires", - "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", - "glossaries.upgrade.feature3": "Importez/exportez via CSV", - "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", - "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", - "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", - "glossaries.upgrade.proLabel": "Pro", - "glossaries.upgrade.upgradeBtn": "Passer à Pro", - "glossaries.loading": "Chargement...", - "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", - "glossaries.howItWorks.step1Title": "Configurez ici", - "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", - "glossaries.howItWorks.step2Title": "Activez dans Traduire", - "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", - "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", - "glossaries.howItWorks.goToTranslate": "Aller à Traduire", - "glossaries.status.unsaved": "Non enregistré", - "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", - "glossaries.status.inactive": "Inactif", - "glossaries.instructions.whatForBold": "À quoi ça sert ?", - "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", - "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", - "glossaries.instructions.charCount": "{count} caractères", - "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", - "glossaries.instructions.clearAll": "Tout effacer", - "glossaries.instructions.saving": "Enregistrement…", - "glossaries.instructions.saved": "Enregistré", - "glossaries.presets.whatForBold": "À quoi ça sert ?", - "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", - "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", - "glossaries.presets.creating": "Création…", - "glossaries.presets.alreadyImported": "Déjà importé", - "glossaries.presets.it.title": "IT / Logiciel", - "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", - "glossaries.presets.legal.title": "Juridique / Contrats", - "glossaries.presets.legal.desc": "Droit des affaires, contentieux", - "glossaries.presets.medical.title": "Médical / Santé", - "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", - "glossaries.presets.finance.title": "Finance / Comptabilité", - "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", - "glossaries.presets.marketing.title": "Marketing / Publicité", - "glossaries.presets.marketing.desc": "Digital, branding, analytics", - "glossaries.presets.hr.title": "RH / Ressources Humaines", - "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", - "glossaries.presets.scientific.title": "Scientifique / Recherche", - "glossaries.presets.scientific.desc": "Publications, thèses, articles", - "glossaries.presets.ecommerce.title": "E-commerce / Vente", - "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", - "glossaries.grid.title": "Vos", - "glossaries.grid.titleHighlight": "glossaires", - "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", - "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", - "glossaries.grid.activeTranslation": "Traduction active :", - "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", - "glossaries.badge.compatible": "Compatible", - "glossaries.badge.otherTarget": "Autre cible", - "glossaries.card.editTerms": "Modifier les termes", - "glossaries.card.created": "Creato", - "glossaries.card.term": "termine", - "glossaries.card.delete": "Supprimer", - "glossaries.grid.searchPlaceholder": "Search a glossary…", - "glossaries.grid.noResults": "No results for this search.", - "glossaries.detail.backToList": "Back to glossaries", - "glossaries.detail.save": "Save", - "glossaries.detail.savedTitle": "Saved", - "glossaries.detail.savedDesc": "The glossary has been updated.", - "glossaries.detail.settingsTitle": "Settings", - "glossaries.detail.sourceLang": "Source language", - "glossaries.detail.targetLang": "Target language", - "glossaries.detail.termsTitle": "Terms", - "glossaries.detail.terms": "terms", - "glossaries.detail.searchTerms": "Filter…", - "glossaries.detail.noTerms": "No terms yet.", - "glossaries.detail.addFirstTerm": "Add the first term", - "glossaries.detail.addTerm": "Add a term", - "glossaries.detail.maxReached": "Maximum limit reached", - "glossaries.detail.source": "Source", - "glossaries.detail.target": "Target", - "glossaries.detail.sourcePlaceholder": "source term", - "glossaries.detail.targetPlaceholder": "target term", - "glossaries.detail.csvTitle": "CSV", - "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", - "glossaries.detail.export": "Export", - "glossaries.detail.import": "Import", - "glossaries.detail.dangerTitle": "Danger zone", - "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", - "glossaries.detail.deleteGlossary": "Delete this glossary", - "glossaries.detail.confirmDelete": "Confirm deletion?", - "glossaries.detail.confirm": "Confirm", - "glossaries.detail.cancel": "Cancel", - "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", - "glossaries.detail.sourceLocked": "fixed", - "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", - "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", - "glossaries.detail.notFoundTitle": "Glossary not found", - "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", - "glossaries.detail.maxTermsTitle": "Limit reached", - "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", - "glossaries.detail.importEmptyTitle": "Empty file", - "glossaries.detail.importEmptyDesc": "No terms detected in this file.", - "glossaries.detail.importedTitle": "Imported", - "glossaries.detail.importedDesc": "{count} terms imported.", - "glossaries.detail.importErrorTitle": "Read error", - "glossaries.detail.importErrorDesc": "Unable to read the file.", - "apiKeys.webhook.title": "Intégration Webhook", - "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", - "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", - "apiKeys.webhook.codeParam": "webhook_url", - "translate.mode.label": "Mode de traduction", - "translate.mode.classic": "Classique", - "translate.mode.classicDesc": "Rapide", - "translate.mode.proLlm": "Pro LLM", - "translate.mode.proLlmDesc": "Contextuel", - "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", - "translate.mode.upgradeLink": "Passer à Pro", - "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", - "pricing.nav.back": "Indietro", - "pricing.nav.home": "Home", - "pricing.nav.mySubscription": "Il mio abbonamento", - "pricing.header.badge": "Modelli IA aggiornati — Marzo 2026", - "pricing.header.title": "Un piano per ogni esigenza", - "pricing.header.subtitle": "Traduci i tuoi documenti Word, Excel e PowerPoint mantenendo la formattazione originale. Nessuna chiave API richiesta.", - "pricing.billing.monthly": "Mensile", - "pricing.billing.yearly": "Annuale", - "pricing.plans.free.name": "Gratuito", - "pricing.plans.starter.name": "Starter", - "pricing.plans.pro.name": "Pro", - "pricing.plans.business.name": "Business", - "pricing.plans.enterprise.name": "Enterprise", - "pricing.plans.free.description": "Perfetto per scoprire l'app", - "pricing.plans.starter.description": "Per privati e piccoli progetti", - "pricing.plans.pro.description": "Per professionisti e team in crescita", - "pricing.plans.business.description": "Per team e organizzazioni", - "pricing.plans.enterprise.description": "Soluzioni personalizzate per grandi organizzazioni", - "pricing.plans.pro.highlight": "Il più popolare", - "pricing.plans.pro.badge": "POPOLARE", - "pricing.plans.enterprise.badge": "SU RICHIESTA", - "pricing.plans.free.feat1": "5 documenti / mese", - "pricing.plans.free.feat2": "Fino a 15 pagine per documento", - "pricing.plans.free.feat3": "Google Traduttore incluso", - "pricing.plans.free.feat4": "Tutte le lingue (130+)", - "pricing.plans.free.feat5": "Supporto della community", - "pricing.plans.starter.feat1": "50 documenti / mese", - "pricing.plans.starter.feat2": "Fino a 50 pagine per documento", - "pricing.plans.starter.feat3": "Google Traduttore + DeepL", - "pricing.plans.starter.feat4": "File fino a 10 MB", - "pricing.plans.starter.feat5": "Supporto via e-mail", - "pricing.plans.starter.feat6": "Cronologia di 30 giorni", - "pricing.plans.pro.feat1": "200 documenti / mese", - "pricing.plans.pro.feat2": "Fino a 200 pagine per documento", - "pricing.plans.pro.feat3": "Traduzione IA Essenziale", - "pricing.plans.pro.feat4": "Google Traduttore + DeepL", - "pricing.plans.pro.feat5": "File fino a 25 MB", - "pricing.plans.pro.feat6": "Glossari personalizzati", - "pricing.plans.pro.feat7": "Supporto prioritario", - "pricing.plans.pro.feat8": "Cronologia di 90 giorni", - "pricing.plans.business.feat1": "1 000 documenti / mese", - "pricing.plans.business.feat2": "Fino a 500 pagine per documento", - "pricing.plans.business.feat3": "IA Essenziale + Premium (Claude Haiku)", - "pricing.plans.business.feat4": "Tutti i provider di traduzione", - "pricing.plans.business.feat5": "File fino a 50 MB", - "pricing.plans.business.feat6": "Accesso API (10 000 chiamate/mese)", - "pricing.plans.business.feat7": "Webhook di notifica", - "pricing.plans.business.feat8": "Supporto dedicato", - "pricing.plans.business.feat9": "Cronologia di 1 anno", - "pricing.plans.business.feat10": "Analisi avanzate", - "pricing.plans.enterprise.feat1": "Documenti illimitati", - "pricing.plans.enterprise.feat2": "Tutti i modelli IA (GPT-5, Claude Opus 4.6…)", - "pricing.plans.enterprise.feat3": "Distribuzione on-premise o cloud dedicato", - "pricing.plans.enterprise.feat4": "SLA 99,9 % garantito", - "pricing.plans.enterprise.feat5": "Supporto dedicato 24/7", - "pricing.plans.enterprise.feat6": "White-label", - "pricing.plans.enterprise.feat7": "Team illimitati", - "pricing.plans.enterprise.feat8": "Integrazioni personalizzate", - "pricing.card.onRequest": "Su richiesta", - "pricing.card.free": "Gratuito", - "pricing.card.perMonth": "/mese", - "pricing.card.billedYearly": "Fatturato {price} € / anno", - "pricing.card.documents": "Documenti", - "pricing.card.pagesMax": "Pagine max", - "pricing.card.aiTranslation": "Traduzione IA", - "pricing.card.unlimited": "Illimitato", - "pricing.card.perMonthStat": "/ mese", - "pricing.card.perDoc": "p / doc", - "pricing.card.aiEssential": "Essenziale", - "pricing.card.aiEssentialPremium": "Essenziale + Premium", - "pricing.card.aiCustom": "Personalizzato", - "pricing.card.myPlan": "Il mio piano", - "pricing.card.managePlan": "Gestisci il mio piano", - "pricing.card.startFree": "Inizia gratuitamente", - "pricing.card.contactUs": "Contattaci", - "pricing.card.choosePlan": "Scegli questo piano", - "pricing.card.processing": "Elaborazione…", - "pricing.comparison.title": "Confronto dettagliato", - "pricing.comparison.subtitle": "Tutto ciò che include ogni piano", - "pricing.comparison.feature": "Funzionalità", - "pricing.comparison.docsPerMonth": "Documenti / mese", - "pricing.comparison.pagesMaxPerDoc": "Pagine max / documento", - "pricing.comparison.maxFileSize": "Dimensione max file", - "pricing.comparison.googleTranslation": "Google Traduttore", - "pricing.comparison.deepl": "DeepL", - "pricing.comparison.aiEssential": "Traduzione IA Essenziale", - "pricing.comparison.aiPremium": "Traduzione IA Premium", - "pricing.comparison.apiAccess": "Accesso API", - "pricing.comparison.priorityProcessing": "Elaborazione prioritaria", - "pricing.comparison.support": "Supporto", - "pricing.comparison.support.community": "Community", - "pricing.comparison.support.email": "E-mail", - "pricing.comparison.support.priority": "Prioritario", - "pricing.comparison.support.dedicated": "Dedicato", - "pricing.comparison.mb": "MB", - "pricing.credits.title": "Crediti aggiuntivi", - "pricing.credits.subtitle": "Ne serve di più? Acquista crediti singoli, senza abbonamento.", - "pricing.credits.perPage": "1 credito = 1 pagina tradotta.", - "pricing.credits.bestValue": "Miglior rapporto qualità-prezzo", - "pricing.credits.unit": "crediti", - "pricing.credits.centsPerCredit": "cts / credito", - "pricing.credits.buy": "Acquista", - "pricing.trust.encryption.title": "Crittografia end-to-end", - "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 a riposo", - "pricing.trust.languages.title": "130+ lingue", - "pricing.trust.languages.sub": "Tra cui arabo, persiano, ebraico (RTL)", - "pricing.trust.parallel.title": "Elaborazione parallela", - "pricing.trust.parallel.sub": "IA multi-thread ultraveloce", - "pricing.trust.availability.title": "Disponibile 24/7", - "pricing.trust.availability.sub": "99,9 % di uptime garantito", - "pricing.aiModels.title": "I nostri modelli IA — Marzo 2026", - "pricing.aiModels.essential.title": "Traduzione IA Essenziale", - "pricing.aiModels.essential.plan": "Piano Pro", - "pricing.aiModels.essential.descPrefix": "Basato su", - "pricing.aiModels.essential.descSuffix": "— il modello IA più conveniente del 2026. Qualità paragonabile ai modelli frontier a una frazione del costo.", - "pricing.aiModels.essential.modelName": "il nostro modello IA Essenziale", - "pricing.aiModels.essential.context": "163K token di contesto", - "pricing.aiModels.essential.value": "Eccellente rapporto qualità-prezzo", - "pricing.aiModels.premium.title": "Traduzione IA Premium", - "pricing.aiModels.premium.plan": "Piano Business", - "pricing.aiModels.premium.descPrefix": "Basato su", - "pricing.aiModels.premium.descSuffix": "di Anthropic — preciso su documenti legali, medici e tecnici complessi.", - "pricing.aiModels.premium.context": "200K token di contesto", - "pricing.aiModels.premium.precision": "Massima precisione", - "pricing.faq.title": "Domande frequenti", - "pricing.faq.q1": "Posso cambiare piano in qualsiasi momento?", - "pricing.faq.a1": "Sì. Il passaggio a un piano superiore è immediato e proporzionale. Il downgrade sarà attivo alla fine del periodo corrente.", - "pricing.faq.q2": "Cos'è la «Traduzione IA Essenziale»?", - "pricing.faq.a2": "È il nostro motore IA. Comprende il contesto dei vostri documenti, preserva il layout e gestisce i termini tecnici molto meglio della traduzione classica.", - "pricing.faq.q3": "Qual è la differenza tra IA Essenziale e IA Premium?", - "pricing.faq.a3": "La IA Essenziale usa un modello ottimizzato (eccellente rapporto qualità/prezzo). La IA Premium usa Claude 3.5 Haiku di Anthropic, più precisa su documenti legali, medici e tecnici complessi.", - "pricing.faq.q4": "I miei documenti vengono conservati dopo la traduzione?", - "pricing.faq.a4": "I file tradotti sono disponibili secondo il tuo piano (30 giorni Starter, 90 giorni Pro, 1 anno Business). Sono crittografati a riposo e in transito.", - "pricing.faq.q5": "Cosa succede se supero la quota mensile?", - "pricing.faq.a5": "Puoi acquistare crediti aggiuntivi singolarmente o fare upgrade del piano. Riceverai una notifica al raggiungimento dell'80 % di utilizzo.", - "pricing.faq.q6": "C'è un periodo di prova gratuito per i piani a pagamento?", - "pricing.faq.a6": "Il piano Gratuito è permanente e non richiede carta di credito. Per i piani Pro e Business, contattaci per una prova di 14 giorni.", - "pricing.faq.q7": "Quali formati di file sono supportati?", - "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx) e presto PDF. Tutti i piani supportano gli stessi formati.", - "pricing.cta.title": "Pronto per iniziare?", - "pricing.cta.subtitle": "Inizia gratuitamente, senza carta di credito. Fai upgrade quando ne hai bisogno.", - "pricing.cta.createAccount": "Crea un account gratuito", - "pricing.cta.login": "Accedi", - "pricing.toast.demo": "Modalità demo — Stripe non è ancora configurato. In produzione, saresti reindirizzato al pagamento per attivare il piano {planId}.", - "pricing.toast.networkError": "Errore di rete. Riprova.", - "pricing.toast.paymentError": "Errore durante la creazione del pagamento.", - "register.title": "Crea un account", - "register.subtitle": "Inizia a tradurre gratuitamente", - "register.error.failed": "Registrazione non riuscita", - "register.name.label": "Nome", - "register.name.placeholder": "Il tuo nome", - "register.name.error": "Il nome deve contenere almeno 2 caratteri", - "register.email.label": "Indirizzo e-mail", - "register.email.placeholder": "tu@esempio.com", - "register.email.error": "Indirizzo e-mail non valido", - "register.password.label": "Password", - "register.password.error": "La password deve contenere almeno 8 caratteri, una maiuscola, una minuscola e una cifra", - "register.password.show": "Mostra password", - "register.password.hide": "Nascondi password", - "register.password.strengthLabel": "Sicurezza:", - "register.password.strength.weak": "Debole", - "register.password.strength.medium": "Media", - "register.password.strength.strong": "Forte", - "register.confirmPassword.label": "Conferma password", - "register.confirmPassword.error": "Le password non coincidono", - "register.confirmPassword.show": "Mostra", - "register.confirmPassword.hide": "Nascondi", - "register.submit.creating": "Creazione account...", - "register.submit.create": "Crea il mio account", - "register.hasAccount": "Hai già un account?", - "register.login": "Accedi", - "register.terms.prefix": "Creando un account, accetti i nostri", - "register.terms.link": "termini di servizio", - "login.errorTitle": "Login Error", - "login.welcomeBack": "Welcome back", - "login.signInToContinue": "Sign in to continue translating", - "login.email": "Email", - "login.emailPlaceholder": "you@example.com", - "login.password": "Password", - "login.forgotPassword": "Forgot password?", - "login.passwordPlaceholder": "••••••••", - "login.signingIn": "Signing in...", - "login.signIn": "Sign In", - "login.noAccount": "Don't have an account?", - "login.signUpFree": "Sign up for free", - "login.orContinueWith": "oppure continua con e-mail", - "login.google.connecting": "Connessione…", - "login.google.errorGeneric": "Si è verificato un errore con l'accesso Google.", - "login.google.errorFailed": "Accesso con Google non riuscito. Riprova.", - "forgotPassword.enterEmail": "Please enter your email address", - "forgotPassword.error": "An error occurred", - "forgotPassword.title": "Forgot Password", - "forgotPassword.checkEmail": "Check your inbox", - "forgotPassword.subtitle": "Enter your email to receive a reset link", - "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", - "forgotPassword.emailLabel": "Email address", - "forgotPassword.emailPlaceholder": "you@example.com", - "forgotPassword.sending": "Sending...", - "forgotPassword.sendLink": "Send reset link", - "forgotPassword.backToLogin": "Back to login", - "forgotPassword.loading": "Loading...", - "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", - "resetPassword.passwordMismatch": "Passwords do not match", - "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", - "resetPassword.error": "An error occurred", - "resetPassword.invalidLink": "Invalid link", - "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", - "resetPassword.requestNewLink": "Request new link", - "resetPassword.successTitle": "Password reset", - "resetPassword.newPasswordTitle": "New password", - "resetPassword.successSubtitle": "You will be redirected to login", - "resetPassword.subtitle": "Set your new password", - "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", - "resetPassword.newPassword": "New password", - "resetPassword.showPassword": "Show password", - "resetPassword.hidePassword": "Hide password", - "resetPassword.confirmPassword": "Confirm password", - "resetPassword.resetting": "Resetting...", - "resetPassword.resetPassword": "Reset password", - "resetPassword.backToLogin": "Back to login", - "resetPassword.loading": "Loading...", - "common.loading": "Caricamento...", - "profile.header.title": "Il mio profilo", - "profile.header.subtitle": "Gestisci il tuo account e le tue preferenze.", - "profile.tabs.account": "Account", - "profile.tabs.subscription": "Abbonamento", - "profile.tabs.preferences": "Preferenze", - "profile.account.user": "Utente", - "profile.account.memberSince": "Membro dal", - "profile.plan.label": "Piano", - "profile.plan.free": "Free", - "profile.plan.starter": "Starter", - "profile.plan.pro": "Pro", - "profile.plan.business": "Business", - "profile.plan.enterprise": "Enterprise", - "profile.plan.pricePerMonth": "{price} €/mese", - "profile.subscription.canceling": "In cancellazione", - "profile.subscription.active": "Attivo", - "profile.subscription.unknown": "Sconosciuto", - "profile.subscription.accessUntil": "Accesso fino al", - "profile.subscription.renewalOn": "Rinnovo il", - "profile.subscription.upgradePlan": "Passa a un piano a pagamento", - "profile.subscription.changePlan": "Cambia piano", - "profile.subscription.manageBilling": "Gestisci fatturazione", - "profile.subscription.billingUnavailable": "Portale di fatturazione non disponibile.", - "profile.subscription.billingError": "Errore di accesso al portale di fatturazione.", - "profile.subscription.cancelSuccess": "Abbonamento cancellato. Mantieni l'accesso fino alla fine del periodo.", - "profile.subscription.cancelError": "Errore durante la cancellazione.", - "profile.subscription.networkError": "Errore di rete.", - "profile.usage.title": "Utilizzo di questo mese", - "profile.usage.resetOn": "Azzeramento il", - "profile.usage.documents": "Documenti", - "profile.usage.pages": "Pagine", - "profile.usage.extraCredits": "credito extra", - "profile.usage.extraCreditsPlural": "crediti extra", - "profile.usage.quotaReached": "Quota raggiunta", - "profile.usage.quotaReachedDesc": "Passa a un piano superiore per continuare.", - "profile.usage.unlockMore": "Sblocca più traduzioni con un piano a pagamento.", - "profile.usage.viewPlans": "Vedi i piani", - "profile.usage.includedInPlan": "Incluso nel tuo piano", - "profile.danger.title": "Zona pericolosa", - "profile.danger.description": "La cancellazione avrà effetto alla fine del periodo corrente. Mantieni l'accesso fino a quella data.", - "profile.danger.confirm": "Sei sicuro? Questa azione non può essere annullata.", - "profile.danger.confirmCancel": "Conferma cancellazione", - "profile.danger.cancelSubscription": "Cancella il mio abbonamento", - "profile.danger.keep": "No, mantieni", - "profile.prefs.interfaceLang": "Lingua dell'interfaccia", - "profile.prefs.interfaceLangDesc": "La lingua viene rilevata automaticamente in base al tuo browser. Puoi cambiarla manualmente.", - "profile.prefs.defaultTargetLang": "Lingua di destinazione predefinita", - "profile.prefs.selectLanguage": "Seleziona una lingua", - "profile.prefs.defaultTargetLangDesc": "Questa lingua sarà preselezionata per le tue traduzioni.", - "profile.prefs.save": "Salva", - "profile.prefs.theme": "Tema", - "profile.prefs.themeDesc": "Scegli l'aspetto dell'interfaccia", - "profile.prefs.cache": "Cache", - "profile.prefs.cacheDesc": "Svuotare la cache locale può risolvere alcuni problemi di visualizzazione.", - "profile.prefs.clearing": "Svuotamento...", - "profile.prefs.clearCache": "Svuota cache", - "settings.title": "Impostazioni", - "settings.subtitle": "Configurazione generale dell'applicazione", - "settings.formats.title": "Formati supportati", - "settings.formats.subtitle": "Tipi di documento che puoi tradurre", - "settings.formats.formulas": "Formule", - "settings.formats.styles": "Stili", - "settings.formats.images": "Immagini", - "settings.formats.headers": "Intestazioni", - "settings.formats.tables": "Tabelle", - "settings.formats.slides": "Diapositive", - "settings.formats.notes": "Note", - "settings.cache.title": "Cache", - "settings.cache.desc": "Svuotare la cache locale può risolvere alcuni problemi di visualizzazione.", - "settings.cache.clearing": "Svuotamento...", - "settings.cache.clear": "Svuota cache", - "services.title": "Fornitori di traduzione", - "services.subtitle": "I fornitori sono configurati dall'amministratore. Puoi vedere quali sono attualmente disponibili per il tuo account.", - "services.loading": "Caricamento fornitori...", - "services.noProviders": "Nessun fornitore attualmente configurato. Contatta il tuo amministratore.", - "services.classic": "Traduzione classica", - "services.llmPro": "LLM · Contestuale (Pro)", - "services.available": "Disponibile", - "services.model": "Modello", - "services.adminOnly.title": "La configurazione dei fornitori è riservata all'amministratore", - "services.adminOnly.desc": "Le chiavi API, la selezione dei modelli e l'attivazione dei fornitori sono gestite esclusivamente dall'amministratore nel pannello admin. Non è necessario inserire alcuna chiave API.", - "apiKeys.title": "Chiavi API", - "apiKeys.subtitle": "Gestisci le tue chiavi API per l'accesso programmatico all'API di traduzione.", - "apiKeys.loading": "Caricamento...", - "apiKeys.sectionTitle": "API e automazione", - "apiKeys.sectionDesc": "Genera e gestisci le tue chiavi API per i flussi di automazione", - "apiKeys.keysUsed": "{total} di {max} chiavi utilizzate", - "apiKeys.maxReached": "Numero massimo di chiavi raggiunto. Revoca una chiave per generarne una nuova.", - "apiKeys.canGenerate": "Puoi generare ancora {count} chiave", - "apiKeys.canGeneratePlural": "Puoi generare ancora {count} chiavi", - "apiKeys.generateNew": "Genera nuova chiave", - "apiKeys.keyRevoked": "Chiave revocata", - "apiKeys.keyRevokedDesc": "La chiave API è stata revocata con successo.", - "apiKeys.keyNotFound": "Chiave non trovata", - "apiKeys.keyNotFoundDesc": "La chiave API non esiste più. Potrebbe essere già stata revocata.", - "apiKeys.error": "Errore", - "apiKeys.revokeError": "Impossibile revocare la chiave API. Riprova.", - "apiKeys.limitReached": "Limite raggiunto", - "apiKeys.limitReachedDesc": "Hai raggiunto il massimo di 10 chiavi API. Revoca una chiave esistente per generarne una nuova.", - "apiKeys.proRequired": "Funzionalità Pro richiesta", - "apiKeys.proRequiredDesc": "Le chiavi API sono una funzionalità Pro. Aggiorna il tuo account.", - "apiKeys.generateError": "Impossibile generare la chiave API. Riprova.", - "apiKeys.upgrade.title": "Chiavi API", - "apiKeys.upgrade.subtitle": "Automatizza le tue traduzioni con l'accesso API", - "apiKeys.upgrade.feat1": "Genera chiavi API illimitate", - "apiKeys.upgrade.feat2": "Automatizza la traduzione dei documenti", - "apiKeys.upgrade.feat3": "Notifiche webhook", - "apiKeys.upgrade.feat4": "Modalità di traduzione LLM", - "apiKeys.upgrade.proFeature": "Le chiavi API sono una funzionalità {pro}. Aggiorna per sbloccare l'automazione API.", - "apiKeys.upgrade.pro": "Pro", - "apiKeys.upgrade.cta": "Passa a Pro", - "apiKeys.dialog.maxTitle": "Numero massimo di chiavi raggiunto", - "apiKeys.dialog.maxDesc": "Hai raggiunto il massimo di 10 chiavi API. Revoca una chiave esistente prima di generarne una nuova.", - "apiKeys.dialog.close": "Chiudi", - "apiKeys.dialog.generated": "Chiave API generata!", - "apiKeys.dialog.generatedDesc": "La tua nuova chiave API è stata creata. Copiala ora - non verrà più mostrata.", - "apiKeys.dialog.important": "Importante:", - "apiKeys.dialog.importantDesc": "Questa è l'unica volta che vedrai questa chiave. Conservala in modo sicuro.", - "apiKeys.dialog.apiKey": "Chiave API", - "apiKeys.dialog.name": "Nome:", - "apiKeys.dialog.done": "Fatto", - "apiKeys.dialog.copied": "Ho copiato la chiave", - "apiKeys.dialog.generateTitle": "Genera nuova chiave API", - "apiKeys.dialog.generateDesc": "Crea una nuova chiave API per l'accesso programmatico all'API di traduzione.", - "apiKeys.dialog.keyName": "Nome chiave (opzionale)", - "apiKeys.dialog.keyNamePlaceholder": "es. Produzione, Staging", - "apiKeys.dialog.keyNameHint": "Un nome descrittivo per identificare questa chiave in seguito.", - "apiKeys.dialog.nameTooLong": "Il nome deve contenere al massimo {max} caratteri", - "apiKeys.dialog.nameInvalid": "Il nome può contenere solo lettere, numeri, spazi, trattini e trattini bassi", - "apiKeys.dialog.cancel": "Annulla", - "apiKeys.dialog.generating": "Generazione...", - "apiKeys.dialog.generate": "Genera chiave", - "apiKeys.table.name": "Nome", - "apiKeys.table.prefix": "Prefisso", - "apiKeys.table.created": "Creata", - "apiKeys.table.lastUsed": "Ultimo utilizzo", - "apiKeys.table.never": "Mai", - "apiKeys.table.actions": "Azioni", - "apiKeys.table.revoke": "Revoca", - "apiKeys.table.copyPrefix": "Copia prefisso chiave", - "apiKeys.table.revokeKey": "Revoca chiave", - "apiKeys.revokeDialog.title": "Revoca chiave API", - "apiKeys.revokeDialog.desc": "Sei sicuro di voler revocare la chiave \"{name}\"? Questa azione non può essere annullata.", - "apiKeys.revokeDialog.confirm": "Sì, revoca", - "apiKeys.revokeDialog.cancel": "Annulla", - "context.proTitle": "Funzionalità Pro", - "context.proDesc": "Il contesto e i glossari professionali sono disponibili con i piani Pro, Business ed Enterprise. Offrono traduzioni più accurate grazie a istruzioni e vocabolario specifici del tuo dominio.", - "context.viewPlans": "Vedi i piani", - "context.title": "Contesto e glossario", - "context.subtitle": "Migliora la qualità della traduzione con istruzioni e vocabolario specifici del tuo dominio.", - "context.presets.title": "Glossari professionali", - "context.presets.desc": "Carica un glossario completo con istruzioni e terminologia specializzata", - "context.instructions.title": "Istruzioni di contesto", - "context.instructions.desc": "Istruzioni che l'IA seguirà durante la traduzione", - "context.instructions.placeholder": "Es.: Traduci documenti tecnici HVAC. Utilizza terminologia ingegneristica precisa...", - "context.glossary.title": "Glossario tecnico", - "context.glossary.desc": "Formato: origine=destinazione (uno per riga). I glossari caricati tramite preset sono modificabili.", - "context.glossary.terms": "termini nel glossario", - "context.clearAll": "Cancella tutto", - "context.saving": "Salvataggio...", - "context.save": "Salva", - "translate.glossary.title": "Glossario", - "translate.glossary.select": "Seleziona glossario", - "translate.glossary.none": "Nessuno", - "translate.glossary.terms": "termini", - "translate.glossary.proOnly": "Passa a Pro per usare i glossari", - "translate.glossary.myGlossaries": "I miei glossari", - "translate.glossary.fromTemplate": "Crea da modello", - "translate.glossary.noGlossaryForPair": "Nessun glossario per", - "translate.glossary.noGlossaries": "Nessun glossario", - "translate.glossary.loading": "Caricamento...", - "translate.glossary.classicMode": "Motore neutro senza glossario (solo IA)", - "translate.glossary.selectPlaceholder": "Selezionare un glossario...", - "translate.glossary.multilingual": "MULTILINGUE", - "translate.glossary.noGlossaryAvailable": "Nessun glossario disponibile", - "translate.glossary.filterByLang": "Filtra per lingua", - "translate.glossary.active": "Attivo", - "translate.glossary.inactive": "Inattivo", - "translate.glossary.availableTemplates": "Modelli disponibili", - "translate.glossary.importing": "Importazione...", - "translate.glossary.imported": "(Importato)", - "translate.glossary.noGlossaryForSource": "Nessun glossario o modello per la lingua di origine", - "translate.glossary.createGlossary": "Crea un glossario", - "translate.glossary.showAll": "Mostra tutti i glossari", - "translate.glossary.activePreview": "Anteprima delle corrispondenze attive:", - "translate.glossary.total": "in totale", - "translate.glossary.moreTerms": "altri termini", - "translate.glossary.noTerms": "Nessun termine in questo glossario.", - "translate.glossary.sourceTerm": "Termine sorgente", - "translate.glossary.translation": "Traduzione", - "translate.glossary.addTerm": "Aggiungi termine", - "translate.glossary.disabledMode": "Motore neutro senza glossario applicato", - "translate.glossary.addTermError": "Errore durante l'aggiunta del termine", - "translate.glossary.networkError": "Errore di rete", - "translate.glossary.importFailed": "Importazione fallita ({status})", - "translate.glossary.helpText": "Il glossario forza la traduzione precisa dei termini. Scegli un glossario la cui lingua sorgente corrisponde alla lingua originale del documento.", - "translate.glossary.sourceWarning": "Attenzione: Questo glossario utilizza la lingua sorgente", - "translate.glossary.sourceWarningBut": "ma il documento è configurato in", - "translate.glossary.targetWarning": "Incompatibilità di destinazione: Questo glossario è progettato per tradurre verso", - "translate.glossary.targetWarningBut": "ma il documento ha come destinazione", - "translate.glossary.targetWarningEnd": "I termini potrebbero non essere pertinenti.", - "context.presets.createGlossary": "Crea glossario", - "context.presets.created": "Glossario creato", - "context.presets.createdDesc": "Il glossario \"{name}\" è stato creato con {count} termini.", - "context.presets.hint": "Fai clic su un preset per creare un glossario con termini specifici del dominio. Gestisci i tuoi glossari nella sezione Glossari.", - "context.glossary.manage": "Gestisci glossari", - "context.saved": "Salvato", - "context.savedDesc": "Le tue istruzioni di contesto sono state salvate.", - "admin.login.title": "Amministrazione", - "admin.login.required": "Accesso richiesto", - "admin.login.password": "Password amministratore", - "admin.login.connecting": "Connessione...", - "admin.login.access": "Accedi al pannello admin", - "admin.login.restricted": "Riservato agli amministratori", - "admin.layout.checking": "Verifica dell'autenticazione...", - "admin.dashboard.title": "Dashboard Admin", - "admin.dashboard.subtitle": "Pannello di controllo amministratore", - "admin.dashboard.refresh": "Aggiorna", - "admin.dashboard.refreshTooltip": "Aggiorna dati dashboard", - "admin.dashboard.config": "Configurazione di sistema", - "admin.dashboard.maxFileSize": "Dimensione max file:", - "admin.dashboard.translationService": "Servizio di traduzione:", - "admin.dashboard.formats": "Formati:", - "admin.nav.dashboard": "Dashboard", - "admin.nav.users": "Utenti", - "admin.nav.pricing": "Prezzi e Stripe", - "admin.nav.providers": "Fornitori", - "admin.nav.system": "Sistema", - "admin.nav.logs": "Log", - "admin.users.title": "Gestione Utenti", - "admin.users.subtitle": "Visualizza e gestisci gli account utente", - "admin.users.planUpdated": "Piano aggiornato", - "admin.users.planChanged": "Il piano è stato modificato in \"{plan}\" con successo.", - "admin.users.unknownError": "Errore sconosciuto", - "admin.users.error": "Errore", - "admin.users.planUpdateError": "Impossibile aggiornare il piano: {message}", - "admin.users.noKeys": "Nessuna chiave", - "admin.users.noKeysDesc": "Questo utente non ha chiavi API attive.", - "admin.users.keysRevoked": "Chiavi revocate", - "admin.users.keysRevokedDesc": "{count} chiave/i API revocata/e con successo.", - "admin.users.revokeError": "Impossibile revocare le chiavi: {message}", - "admin.users.retry": "Riprova", - "admin.system.title": "Sistema", - "admin.system.subtitle": "Monitora lo stato del sistema e gestisci le risorse", - "admin.system.quotas": "Quote di traduzione", - "admin.system.resetQuotas": "Ripristina quote mensili", - "admin.system.resetting": "Ripristino...", - "admin.system.reset": "Ripristina", - "admin.system.allOperational": "Tutti i sistemi operativi", - "admin.system.issuesDetected": "Problemi di sistema rilevati", - "admin.system.waitingData": "In attesa di dati...", - "admin.system.purging": "Pulizia in corso...", - "admin.system.clean": "Pulisci", - "admin.system.purge": "Pulisci", - "memento.title": "Scopri Momento", - "memento.slogan": "Momento non è solo un'app di note. È un ecosistema intelligente che connette, analizza e sviluppa le tue idee in tempo reale usando 6 agenti IA e ricerca semantica avanzata.", - "memento.ctaFree": "Inizia gratis", - "memento.ctaMore": "Scopri di più", - "common.backToHome": "Torna alla home", - "dashboard.topbar.interfaceLabel": "Interfaccia di traduzione", - "dashboard.topbar.premiumAccess": "Accesso Premium", - "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", - "layout.nav.apiAccess": "Accesso API", - "layout.footer.terms": "Termini", - "layout.footer.privacy": "Privacy", - "fileUploader.uploadDocument": "Carica documento", - "fileUploader.uploadDesc": "Trascina o fai clic per selezionare un file (Excel, Word, PowerPoint)", - "fileUploader.dropHere": "Rilascia il file qui…", - "fileUploader.dragAndDrop": "Trascina il documento qui", - "fileUploader.orClickBrowse": "oppure fai clic per sfogliare", - "fileUploader.preview": "Anteprima", - "fileUploader.translationOptions": "Opzioni di traduzione", - "fileUploader.configureSettings": "Configura le impostazioni di traduzione", - "fileUploader.targetLanguage": "Lingua di destinazione", - "fileUploader.selectLanguage": "Seleziona lingua", - "fileUploader.translationProvider": "Provider di traduzione", - "fileUploader.selectProvider": "Seleziona provider", - "fileUploader.advancedOptions": "Opzioni avanzate", - "fileUploader.translateImages": "Traduci immagini", - "fileUploader.translating": "Traduzione in corso…", - "fileUploader.translateDocument": "Traduci documento", - "fileUploader.processing": "Elaborazione…", - "fileUploader.translationError": "Errore di traduzione", - "fileUploader.translationComplete": "Traduzione completata!", - "fileUploader.translationCompleteDesc": "Il documento è stato tradotto con successo mantenendo la formattazione.", - "fileUploader.download": "Scarica documento tradotto", - "fileUploader.webgpuUnsupported": "WebGPU non è supportato in questo browser. Usa Chrome 113+ o Edge 113+.", - "fileUploader.webllmNotLoaded": "Modello WebLLM non caricato. Vai a Impostazioni > Servizi di traduzione per caricare un modello.", - "fileUploader.extracting": "Estrazione dei testi dal documento…", - "fileUploader.noTranslatable": "Nessun testo traducibile trovato nel documento", - "fileUploader.foundTexts": "Trovati {count} testi da tradurre", - "fileUploader.translatingItem": "Traduzione {current}/{total}: «{preview}»", - "fileUploader.reconstructing": "Ricostruzione del documento…", - "fileUploader.translatingLocally": "Traduzione locale con WebLLM…", - "checkout.activating": "Attivazione in corso…", - "checkout.activatingDesc": "Stiamo aggiornando il tuo abbonamento, attendi.", - "checkout.paymentConfirmed": "Pagamento confermato!", - "checkout.subscriptionActivated": "Abbonamento attivato!", - "checkout.planActivated": "Piano {plan} attivato!", - "checkout.redirectingToProfile": "Reindirizzamento al tuo profilo…", - "checkout.paymentReceived": "Pagamento ricevuto", - "checkout.redirecting": "Reindirizzamento…", - "checkout.syncError": "Errore di sincronizzazione", - "checkout.networkError": "Errore di rete. Il pagamento è confermato — ricarica il profilo.", - "dashboard.checkoutSyncError": "Errore di sincronizzazione del pagamento.", - "dashboard.networkRefresh": "Errore di rete. Aggiorna la pagina.", - "dashboard.continueToTranslate": "Vai alla traduzione", - "langSelector.search": "Cerca…", - "langSelector.noResults": "Nessun risultato", - "langSelector.source": "Origine", - "langSelector.target": "Destinazione", - "langSelector.swap": "Inverti", - "translateComplete.highQuality": "Alta qualità", - "translateComplete.segments": "Segmenti", - "translateComplete.characters": "Caratteri", - "translateComplete.confidence": "Affidabilità", - "providerTheme.deepseek.badge": "Essenziale", - "providerTheme.deepseek.subBadge": "Tecnico ed economico", - "providerTheme.deepseek.desc": "Traduzione ultra-precisa ed economica, ideale per documenti tecnici e codice.", - "providerTheme.openai.badge": "Premium", - "providerTheme.openai.subBadge": "Alta fedeltà", - "providerTheme.openai.desc": "Lo standard globale dell'IA. Massima coerenza testuale e rispetto rigoroso dello stile.", - "providerTheme.minimax.badge": "Avanzata", - "providerTheme.minimax.subBadge": "Prestazioni", - "providerTheme.minimax.desc": "Velocità di esecuzione incredibile e comprensione eccellente di strutture complesse.", - "providerTheme.openrouter.badge": "Express", - "providerTheme.openrouter.subBadge": "Multi-modello", - "providerTheme.openrouter.desc": "Accesso unificato ai migliori modelli open-source ottimizzati per la traduzione.", - "providerTheme.openrouter_premium.badge": "Ultra", - "providerTheme.openrouter_premium.subBadge": "Contesto massimo", - "providerTheme.openrouter_premium.desc": "Assistito da modelli all'avanguardia (GPT-4o, Claude Sonnet 4.6) per documenti lunghi.", - "providerTheme.zai.badge": "Specializzata", - "providerTheme.zai.subBadge": "Finanza e Diritto", - "providerTheme.zai.desc": "Modello ottimizzato per terminologie aziendali impegnative (legale, finanza).", - "providerTheme.default.badge": "Moderno", - "providerTheme.default.subBadge": "Ragionamento IA", - "providerTheme.default.desc": "Traduzione con modello linguistico di grandi dimensioni (LLM) con analisi semantica avanzata.", - "providerTheme.classic.google.label": "Google Traduttore", - "providerTheme.classic.google.desc": "Traduzione ultra-veloce che copre oltre 130 lingue. Consigliata per flussi generali.", - "providerTheme.classic.deepl.label": "DeepL Pro", - "providerTheme.classic.deepl.desc": "Traduzione ad alta precisione rinomata per la sua fluidità e formulazioni naturali.", - "providerTheme.classic.google_cloud.label": "Google Cloud API", - "providerTheme.classic.google_cloud.desc": "Motore cloud professionale ottimizzato per l'elaborazione di grandi volumi di documenti.", - "providerSelector.noClassic": "Nessun traduttore standard disponibile.", - "providerSelector.noLlm": "Nessun modello IA configurato.", - "providerSelector.costOne": "Costo: 1 credito per pagina", - "providerSelector.costFive": "Costo: 5 crediti per pagina (Fattore Premium)", - "providerSelector.unlockContextual": "Sblocca la traduzione contestuale premium per i tuoi documenti interi.", - "translate.header.processing": "Elaborazione in corso", - "translate.header.aiActive": "Analisi IA attiva", - "translate.header.aiActiveDesc": "Il tuo layout viene preservato dal nostro motore contestuale.", - "translate.header.completed": "Completato", - "translate.header.completedTitle": "Traduzione completata", - "translate.header.proSpace": "Spazio Pro", - "translate.header.translateDoc": "Traduci un documento", - "translate.header.translateDocDesc": "Preserva il layout originale con il nostro motore di traduzione ultra-alta-fedeltà.", - "translate.upload.nativeFormat": "Formato nativo", - "translate.fileType.word": "Word (.docx)", - "translate.fileType.excel": "Excel (.xlsx)", - "translate.fileType.slides": "Diapositive (.pptx)", - "translate.fileType.pdf": "PDF (.pdf)", - "translate.startTranslation": "Avvia traduzione", - "translate.submit": "Invio…", - "translate.chooseTargetLang": "Seleziona una lingua di destinazione", - "translate.pleaseLoadFile": "Carica prima un file", - "translate.contextEngineActive": "Motore contestuale attivo", - "translate.phase1": "Fase 1: Inizializzazione", - "translate.phase2": "Fase 2: Ricostruzione contestuale", - "translate.stat.segments": "segmenti", - "translate.stat.precision": "precisione", - "translate.stat.speedLabel": "velocità", - "translate.stat.turbo": "Turbo", - "translate.stat.time": "tempo", - "translate.complete.masterQuality": "✓ Qualità master", - "translate.download": "Scarica", - "translate.newTranslation": "+ Nuova traduzione", - "translate.failedTitle": "Errore di traduzione", - "translate.retry": "Riprova", - "translate.uploadAnother": "Carica un altro file", - "translate.monitor": "Monitor IA", - "translate.summary": "Riepilogo", - "translate.cancelProcess": "⟳ Annulla il processo", - "translate.layoutIntegrity": "Integrità del layout", - "translate.secureHundred": "100% SICURO", - "translate.okHundred": "100% OK", - "translate.preserveLayout": "Mantieni layout", - "translate.preserveLayoutDesc": "Mantieni il layout", - "translate.textOnly": "Solo testo", - "translate.textOnlyDesc": "Traduzione rapida solo del testo", - "translate.unavailableStandard": "Non disponibile in modalità Standard (solo IA)", - "apiKeys.noKeysGenerated": "Nessuna chiave generata", - "apiKeys.copied": "Copiato!", - "services.fallback.google.label": "Google Traduttore", - "services.fallback.google.desc": "Traduzione rapida, oltre 130 lingue", - "settings.formats.excel.name": "Excel", - "settings.formats.word.name": "Word", - "settings.formats.powerpoint.name": "PowerPoint", - "pricing.dashboard": "Dashboard", - "pricing.okSymbol": "✓", - "pricing.errSymbol": "✕", - }, - // ═══════════════════════════════════════════════════════════════ - // DUTCH (nl) - // ═══════════════════════════════════════════════════════════════ - nl: { - "auth.brandName": "Wordly", - "dashboard.nav.translate": "Vertalen", - "dashboard.nav.profile": "Mijn profiel", - "dashboard.nav.settings": "Instellingen", - "dashboard.nav.context": "Context", - "dashboard.nav.services": "Diensten", - "dashboard.nav.apiKeys": "API-sleutels", - "dashboard.nav.glossaries": "Woordenlijsten", - "dashboard.header.title": "Dashboard", - "dashboard.header.subtitle": "Beheer uw vertalingen", - "dashboard.header.toggleMenu": "Menu", - "dashboard.header.profileTitle": "Mijn profiel", - "dashboard.sidebar.theme": "Thema", - "dashboard.sidebar.signOut": "Uitloggen", - "dashboard.sidebar.backHome": "Terug naar home", - "dashboard.sidebar.upgradeToPro": "Upgrade naar Pro →", - "cookieConsent.title": "Cookies op Wordly", - "cookieConsent.description": "We gebruiken essentiële cookies zodat de app werkt (sessie, beveiliging, taal). Met uw toestemming gebruiken we ook optionele cookies om verkeer te meten en het product te verbeteren.", - "cookieConsent.acceptAll": "Alles accepteren", - "cookieConsent.essentialOnly": "Alleen essentiële", - "cookieConsent.learnMore": "Meer informatie", - "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.", - "dashboard.translate.pageTitle": "Document vertalen", - "dashboard.translate.pageSubtitle": "Importeer een bestand en kies de doeltaal", - "dashboard.translate.errorNotificationTitle": "Fout", - "dashboard.translate.dropzone.uploadAria": "Bestandsdropzone", - "dashboard.translate.dropzone.title": "Sleep uw bestand hierheen", - "dashboard.translate.dropzone.subtitle": "of klik om te selecteren (DOCX, XLSX, PPTX, PDF)", - "dashboard.translate.dropzone.replaceFile": "Bestand vervangen", - "dashboard.translate.language.source": "Brontaal", - "dashboard.translate.language.target": "Doeltaal", - "dashboard.translate.language.loading": "Talen laden…", - "dashboard.translate.language.autoDetect": "Automatisch detecteren", - "dashboard.translate.language.selectPlaceholder": "Selecteren…", - "dashboard.translate.language.loadErrorPrefix": "Fout bij laden van talen", - "dashboard.translate.provider.loading": "Providers laden…", - "dashboard.translate.provider.noneConfigured": "Geen providers geconfigureerd", - "dashboard.translate.provider.modelTitle": "Model", - "dashboard.translate.provider.sectionTitle": "Provider", - "dashboard.translate.provider.llmDivider": "AI · Contextbewust", - "dashboard.translate.provider.llmDividerPro": "AI · Contextbewust (Pro)", - "dashboard.translate.provider.upgrade": "Upgrade naar Pro", - "dashboard.translate.provider.upgradeSuffix": "om AI-vertaling te ontgrendelen", - "dashboard.translate.trust.zeroRetention": "Geen retentie", - "dashboard.translate.trust.deletedAfter": "Bestanden verwijderd na verwerking", - "dashboard.translate.actions.uploading": "Uploaden…", - "dashboard.translate.actions.translate": "Vertalen", - "dashboard.translate.actions.filePrefix": "Bestand: ", - "dashboard.translate.actions.cancel": "Annuleren", - "dashboard.translate.actions.tryAgain": "Opnieuw proberen", - "dashboard.translate.steps.uploading": "Bestand uploaden…", - "dashboard.translate.steps.starting": "Vertaling starten…", - "dashboard.translate.complete.title": "Vertaling voltooid!", - "dashboard.translate.complete.descNamed": "Uw bestand {name} is succesvol vertaald.", - "dashboard.translate.complete.descGeneric": "Uw bestand is succesvol vertaald.", - "dashboard.translate.complete.downloading": "Downloaden…", - "dashboard.translate.complete.download": "Downloaden", - "dashboard.translate.complete.newTranslation": "Nieuwe vertaling", - "dashboard.translate.complete.toastOkTitle": "Succes", - "dashboard.translate.complete.toastOkDesc": "{name} is succesvol gedownload.", - "dashboard.translate.complete.toastFailTitle": "Mislukt", - "dashboard.translate.complete.toastFailDesc": "Vertaling mislukt. Probeer het opnieuw.", - "dashboard.translate.sourceDocument": "Brondocument", - "dashboard.translate.configuration": "Configuratie", - "dashboard.translate.translating": "Vertaling bezig", - "dashboard.translate.liveMonitor": "Live monitor", - "dashboard.translate.summary": "Samenvatting", - "dashboard.translate.engine": "Engine", - "dashboard.translate.confidence": "Vertrouwen", - "dashboard.translate.cancel": "Annuleren", - "dashboard.translate.segments": "Segmenten", - "dashboard.translate.characters": "Tekens", - "dashboard.translate.elapsed": "Verstreken", - "dashboard.translate.segPerMin": "Seg/min", - "dashboard.translate.highQuality": "Hoge kwaliteit", - "dashboard.translate.quality": "Kwaliteit", - "dashboard.translate.completed": "Vertaling voltooid", - "dashboard.translate.replace": "Vervangen", - "dashboard.translate.pdfMode.title": "PDF-vertaalmodus", - "dashboard.translate.pdfMode.preserveLayout": "Indeling behouden", - "dashboard.translate.pdfMode.textOnly": "Alleen tekst", - "dashboard.translate.pdfMode.preserveLayoutDesc": "Behoudt afbeeldingen, tabellen en opmaak. Ideaal voor eenvoudige PDF's.", - "dashboard.translate.pdfMode.textOnlyDesc": "Vertaalt alle tekst perfect. Schone uitvoer, geen opmaakproblemen.", - "dashboard.translate.pipeline.upload": "Uploaden", - "dashboard.translate.pipeline.analyze": "Analyseren", - "dashboard.translate.pipeline.translate": "Vertaling", - "dashboard.translate.pipeline.rebuild": "Reconstrueren", - "dashboard.translate.pipeline.finalize": "Afronden", - "dashboard.translate.progress.processingFallback": "Verwerken…", - "dashboard.translate.progress.connectionLost": "Verbinding verloren. Opnieuw proberen…", - "dashboard.translate.progress.failedTitle": "Vertaling mislukt", - "dashboard.translate.error.unexpected": "Er is een onverwachte fout opgetreden. Probeer het opnieuw.", - "dashboard.translate.error.noResult": "De vertaling leverde geen resultaten op. Controleer of het document tekst bevat en probeer het opnieuw of kies een andere engine.", - "dashboard.translate.error.apiKey": "Ongeldige of ontbrekende API-sleutel. Neem contact op met de beheerder om API-sleutels te configureren.", - "dashboard.translate.error.quota": "Gebruikslimiet bereikt. Probeer het over een paar minuten opnieuw of kies een andere engine.", - "dashboard.translate.error.timeout": "Verbinding met de vertaalservice is verlopen. Controleer uw netwerk en probeer het opnieuw.", - "dashboard.translate.error.sessionExpired": "Sessie verlopen. Klik op Opnieuw proberen om de vertaling te herstarten.", - "dashboard.translate.error.empty": "Het document lijkt leeg of bevat geen vertaalbare tekst (gescande PDF?).", - "dashboard.translate.error.unsupported": "Niet-ondersteund bestandsformaat of beschadigd bestand.", - "dashboard.translate.error.connection": "Verbinding verbroken. Controleer uw netwerk en probeer het opnieuw.", - "dashboard.translate.error.generic": "Vertaling mislukt: {detail}", - "dashboard.translate.error.title": "Vertaling mislukt", - "dashboard.translate.retry": "Probeer opnieuw", - "dashboard.translate.newFile": "Nieuw bestand", - "dashboard.translate.modeAI": "AI-modus", - "dashboard.translate.modeClassic": "Klassieke modus", - "dashboard.translate.glossaryLLMHint": "Woordenlijsten beschikbaar in AI-modus", - "dashboard.translate.submitting": "Bezig met verzenden...", - "dashboard.translate.submit": "Vertaling starten", - "dashboard.translate.noFile": "Upload eerst een bestand", - "dashboard.translate.noTargetLang": "Selecteer een doeltaal", - "glossaries.yourGlossaries": "Uw woordenlijsten", - "glossaries.title": "Woordenlijsten & Context", - "glossaries.description": "Beheer uw woordenlijsten en contextinstructies voor nauwkeurigere vertalingen.", - "glossaries.createNew": "Nieuwe maken", - "glossaries.empty": "Nog geen woordenlijsten", - "glossaries.emptyDesc": "Maak uw eerste woordenlijst of laad een professionele preset hierboven", - "glossaries.defineTerms": "termen", - "glossaries.aboutTitle": "Over woordenlijsten", - "glossaries.aboutDesc": "Met woordenlijsten kunt u exacte vertalingen definiëren voor specifieke termen. Bij het vertalen worden de termen uit de woordenlijst gebruikt voor consistente en nauwkeurige vertalingen.", - "glossaries.aboutFormat": "Elke term heeft een brontaalwoord en vertalingen in meerdere talen. Selecteer een woordenlijst op de vertaalpagina om deze toe te passen.", - "glossaries.toast.created": "Woordenlijst gemaakt", - "glossaries.toast.createdDesc": "De woordenlijst \"{name}\" is gemaakt.", - "glossaries.toast.imported": "Woordenlijst geïmporteerd", - "glossaries.toast.importedDesc": "De woordenlijst \"{name}\" is geïmporteerd.", - "glossaries.toast.updated": "Woordenlijst bijgewerkt", - "glossaries.toast.updatedDesc": "De woordenlijst \"{name}\" is bijgewerkt.", - "glossaries.toast.deleted": "Woordenlijst verwijderd", - "glossaries.toast.deletedDesc": "De woordenlijst is verwijderd.", - "glossaries.toast.error": "Fout", - "glossaries.toast.errorCreate": "Kan woordenlijst niet maken", - "glossaries.toast.errorImport": "Kan woordenlijst niet importeren", - "glossaries.toast.errorUpdate": "Kan woordenlijst niet bijwerken", - "glossaries.toast.errorDelete": "Kan woordenlijst niet verwijderen", - "glossaries.dialog.title": "Nieuwe woordenlijst", - "glossaries.dialog.description": "Maak een woordenlijst voor uw vertalingen", - "glossaries.dialog.nameLabel": "Naam", - "glossaries.dialog.namePlaceholder": "Mijn woordenlijst", - "glossaries.dialog.tabTemplates": "Sjablonen", - "glossaries.dialog.tabFile": "Bestand", - "glossaries.dialog.tabManual": "Handmatig", - "glossaries.dialog.cancel": "Annuleren", - "glossaries.dialog.creating": "Aanmaken…", - "glossaries.dialog.importing": "Importeren…", - "glossaries.dialog.importBtn": "Importeren", - "glossaries.dialog.selectPrompt": "Selecteren", - "glossaries.dialog.createBtn": "Aanmaken", - "glossaries.dialog.createEmpty": "Leeg aanmaken", - "glossaries.dialog.terms": "termen", - "glossaries.dialog.templatesDesc": "Kies een vooraf gedefinieerd sjabloon", - "glossaries.dialog.templatesEmpty": "Geen sjablonen beschikbaar", - "glossaries.dialog.dropTitle": "Sleep een CSV-bestand hierheen", - "glossaries.dialog.dropOr": "of", - "glossaries.dialog.dropFormats": "CSV, TSV, TXT", - "glossaries.termEditor.addTerm": "Term toevoegen", - "glossaries.termEditor.maxReached": "Maximum van {max} termen per glossarium bereikt.", - "glossaries.dialog.formatTitle": "Indeling", - "glossaries.dialog.formatDesc": "bron,doel (één per regel)", - "glossaries.dialog.formatNote": "Eerste regel overgeslagen als koptekst wordt gedetecteerd", - "glossaries.dialog.errorFormat": "Niet-ondersteunde indeling", - "glossaries.dialog.errorSize": "Bestand te groot", - "glossaries.dialog.errorEmpty": "Leeg bestand", - "glossaries.dialog.errorRead": "Leesfout", - "glossaries.dialog.parsing": "Verwerken…", - "glossaries.dialog.termsImported": "termen geïmporteerd", - "glossaries.dialog.changeFile": "Bestand wijzigen", - "glossaries.dialog.retry": "Opnieuw proberen", - "glossaries.edit.title": "Modifier le glossaire", - "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", - "glossaries.edit.nameLabel": "Nom du glossaire", - "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", - "glossaries.edit.sourceLang": "Langue source", - "glossaries.edit.targetLang": "Langue cible", - "glossaries.edit.termsLabel": "Termes ({count} valides)", - "glossaries.edit.exportCsv": "Exporter CSV", - "glossaries.edit.importCsv": "Importer CSV", - "glossaries.edit.cancel": "Annuler", - "glossaries.edit.saving": "Enregistrement...", - "glossaries.edit.saveChanges": "Enregistrer les modifications", - "glossaries.edit.importFailedTitle": "Échec de l'importation", - "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", - "glossaries.edit.importSuccessTitle": "Importation réussie", - "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", - "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", - "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", - "glossaries.delete.title": "Supprimer le glossaire", - "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", - "glossaries.delete.warning": "Cette action est irréversible", - "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", - "glossaries.delete.cancel": "Annuler", - "glossaries.delete.deleting": "Suppression...", - "glossaries.delete.deleteBtn": "Supprimer", - "glossaries.upgrade.title": "Glossaires", - "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", - "glossaries.upgrade.feature1": "Créez plusieurs glossaires", - "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", - "glossaries.upgrade.feature3": "Importez/exportez via CSV", - "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", - "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", - "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", - "glossaries.upgrade.proLabel": "Pro", - "glossaries.upgrade.upgradeBtn": "Passer à Pro", - "glossaries.loading": "Chargement...", - "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", - "glossaries.howItWorks.step1Title": "Configurez ici", - "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", - "glossaries.howItWorks.step2Title": "Activez dans Traduire", - "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", - "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", - "glossaries.howItWorks.goToTranslate": "Aller à Traduire", - "glossaries.status.unsaved": "Non enregistré", - "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", - "glossaries.status.inactive": "Inactif", - "glossaries.instructions.whatForBold": "À quoi ça sert ?", - "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", - "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", - "glossaries.instructions.charCount": "{count} caractères", - "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", - "glossaries.instructions.clearAll": "Tout effacer", - "glossaries.instructions.saving": "Enregistrement…", - "glossaries.instructions.saved": "Enregistré", - "glossaries.presets.whatForBold": "À quoi ça sert ?", - "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", - "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", - "glossaries.presets.creating": "Création…", - "glossaries.presets.alreadyImported": "Déjà importé", - "glossaries.presets.it.title": "IT / Logiciel", - "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", - "glossaries.presets.legal.title": "Juridique / Contrats", - "glossaries.presets.legal.desc": "Droit des affaires, contentieux", - "glossaries.presets.medical.title": "Médical / Santé", - "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", - "glossaries.presets.finance.title": "Finance / Comptabilité", - "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", - "glossaries.presets.marketing.title": "Marketing / Publicité", - "glossaries.presets.marketing.desc": "Digital, branding, analytics", - "glossaries.presets.hr.title": "RH / Ressources Humaines", - "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", - "glossaries.presets.scientific.title": "Scientifique / Recherche", - "glossaries.presets.scientific.desc": "Publications, thèses, articles", - "glossaries.presets.ecommerce.title": "E-commerce / Vente", - "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", - "glossaries.grid.title": "Vos", - "glossaries.grid.titleHighlight": "glossaires", - "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", - "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", - "glossaries.grid.activeTranslation": "Traduction active :", - "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", - "glossaries.badge.compatible": "Compatible", - "glossaries.badge.otherTarget": "Autre cible", - "glossaries.card.editTerms": "Modifier les termes", - "glossaries.card.created": "Aangemaakt", - "glossaries.card.term": "term", - "glossaries.card.delete": "Supprimer", - "glossaries.grid.searchPlaceholder": "Search a glossary…", - "glossaries.grid.noResults": "No results for this search.", - "glossaries.detail.backToList": "Back to glossaries", - "glossaries.detail.save": "Save", - "glossaries.detail.savedTitle": "Saved", - "glossaries.detail.savedDesc": "The glossary has been updated.", - "glossaries.detail.settingsTitle": "Settings", - "glossaries.detail.sourceLang": "Source language", - "glossaries.detail.targetLang": "Target language", - "glossaries.detail.termsTitle": "Terms", - "glossaries.detail.terms": "terms", - "glossaries.detail.searchTerms": "Filter…", - "glossaries.detail.noTerms": "No terms yet.", - "glossaries.detail.addFirstTerm": "Add the first term", - "glossaries.detail.addTerm": "Add a term", - "glossaries.detail.maxReached": "Maximum limit reached", - "glossaries.detail.source": "Source", - "glossaries.detail.target": "Target", - "glossaries.detail.sourcePlaceholder": "source term", - "glossaries.detail.targetPlaceholder": "target term", - "glossaries.detail.csvTitle": "CSV", - "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", - "glossaries.detail.export": "Export", - "glossaries.detail.import": "Import", - "glossaries.detail.dangerTitle": "Danger zone", - "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", - "glossaries.detail.deleteGlossary": "Delete this glossary", - "glossaries.detail.confirmDelete": "Confirm deletion?", - "glossaries.detail.confirm": "Confirm", - "glossaries.detail.cancel": "Cancel", - "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", - "glossaries.detail.sourceLocked": "fixed", - "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", - "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", - "glossaries.detail.notFoundTitle": "Glossary not found", - "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", - "glossaries.detail.maxTermsTitle": "Limit reached", - "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", - "glossaries.detail.importEmptyTitle": "Empty file", - "glossaries.detail.importEmptyDesc": "No terms detected in this file.", - "glossaries.detail.importedTitle": "Imported", - "glossaries.detail.importedDesc": "{count} terms imported.", - "glossaries.detail.importErrorTitle": "Read error", - "glossaries.detail.importErrorDesc": "Unable to read the file.", - "apiKeys.webhook.title": "Intégration Webhook", - "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", - "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", - "apiKeys.webhook.codeParam": "webhook_url", - "translate.mode.label": "Mode de traduction", - "translate.mode.classic": "Classique", - "translate.mode.classicDesc": "Rapide", - "translate.mode.proLlm": "Pro LLM", - "translate.mode.proLlmDesc": "Contextuel", - "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", - "translate.mode.upgradeLink": "Passer à Pro", - "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", - "pricing.nav.back": "Terug", - "pricing.nav.home": "Home", - "pricing.nav.mySubscription": "Mijn abonnement", - "pricing.header.badge": "AI-modellen bijgewerkt — maart 2026", - "pricing.header.title": "Een abonnement voor elke behoefte", - "pricing.header.subtitle": "Vertaal uw Word-, Excel- en PowerPoint-documenten met behoud van de originele opmaak. Geen API-sleutel vereist.", - "pricing.billing.monthly": "Maandelijks", - "pricing.billing.yearly": "Jaarlijks", - "pricing.plans.free.name": "Gratis", - "pricing.plans.starter.name": "Starter", - "pricing.plans.pro.name": "Pro", - "pricing.plans.business.name": "Business", - "pricing.plans.enterprise.name": "Enterprise", - "pricing.plans.free.description": "Perfect om de app te ontdekken", - "pricing.plans.starter.description": "Voor particulieren en kleine projecten", - "pricing.plans.pro.description": "Voor professionals en groeiende teams", - "pricing.plans.business.description": "Voor teams en organisaties", - "pricing.plans.enterprise.description": "Maatwerkoplossingen voor grote organisaties", - "pricing.plans.pro.highlight": "Meest gekozen", - "pricing.plans.pro.badge": "POPULAIR", - "pricing.plans.enterprise.badge": "OP AANVRAAG", - "pricing.plans.free.feat1": "5 documenten / maand", - "pricing.plans.free.feat2": "Tot 15 pagina's per document", - "pricing.plans.free.feat3": "Google Vertalen inbegrepen", - "pricing.plans.free.feat4": "Alle talen (130+)", - "pricing.plans.free.feat5": "Communitysupport", - "pricing.plans.starter.feat1": "50 documenten / maand", - "pricing.plans.starter.feat2": "Tot 50 pagina's per document", - "pricing.plans.starter.feat3": "Google Vertalen + DeepL", - "pricing.plans.starter.feat4": "Bestanden tot 10 MB", - "pricing.plans.starter.feat5": "E-mailsupport", - "pricing.plans.starter.feat6": "30 dagen geschiedenis", - "pricing.plans.pro.feat1": "200 documenten / maand", - "pricing.plans.pro.feat2": "Tot 200 pagina's per document", - "pricing.plans.pro.feat3": "Essentiële IA-vertaling", - "pricing.plans.pro.feat4": "Google Vertalen + DeepL", - "pricing.plans.pro.feat5": "Bestanden tot 25 MB", - "pricing.plans.pro.feat6": "Aangepaste woordenlijsten", - "pricing.plans.pro.feat7": "Prioriteitssupport", - "pricing.plans.pro.feat8": "90 dagen geschiedenis", - "pricing.plans.business.feat1": "1 000 documenten / maand", - "pricing.plans.business.feat2": "Tot 500 pagina's per document", - "pricing.plans.business.feat3": "Basis- + Premium-AI (Claude Haiku)", - "pricing.plans.business.feat4": "Alle vertaalproviders", - "pricing.plans.business.feat5": "Bestanden tot 50 MB", - "pricing.plans.business.feat6": "API-toegang (10 000 aanroepen/maand)", - "pricing.plans.business.feat7": "Meldingswebhooks", - "pricing.plans.business.feat8": "Dedicated support", - "pricing.plans.business.feat9": "1 jaar geschiedenis", - "pricing.plans.business.feat10": "Geavanceerde analyses", - "pricing.plans.enterprise.feat1": "Onbeperkte documenten", - "pricing.plans.enterprise.feat2": "Alle AI-modellen (GPT-5, Claude Opus 4.6…)", - "pricing.plans.enterprise.feat3": "On-premise of dedicated cloud", - "pricing.plans.enterprise.feat4": "99,9 % SLA gegarandeerd", - "pricing.plans.enterprise.feat5": "24/7 dedicated support", - "pricing.plans.enterprise.feat6": "White-label", - "pricing.plans.enterprise.feat7": "Onbeperkte teams", - "pricing.plans.enterprise.feat8": "Maatwerkintegraties", - "pricing.card.onRequest": "Op aanvraag", - "pricing.card.free": "Gratis", - "pricing.card.perMonth": "/maand", - "pricing.card.billedYearly": "Gefactureerd {price} € / jaar", - "pricing.card.documents": "Documenten", - "pricing.card.pagesMax": "Max. pagina's", - "pricing.card.aiTranslation": "AI-vertaling", - "pricing.card.unlimited": "Onbeperkt", - "pricing.card.perMonthStat": "/ maand", - "pricing.card.perDoc": "p / doc", - "pricing.card.aiEssential": "Basis", - "pricing.card.aiEssentialPremium": "Basis + Premium", - "pricing.card.aiCustom": "Maatwerk", - "pricing.card.myPlan": "Mijn abonnement", - "pricing.card.managePlan": "Abonnement beheren", - "pricing.card.startFree": "Gratis starten", - "pricing.card.contactUs": "Neem contact op", - "pricing.card.choosePlan": "Dit abonnement kiezen", - "pricing.card.processing": "Verwerken…", - "pricing.comparison.title": "Gedetailleerde vergelijking", - "pricing.comparison.subtitle": "Alles wat in elk abonnement is inbegrepen", - "pricing.comparison.feature": "Functie", - "pricing.comparison.docsPerMonth": "Documenten / maand", - "pricing.comparison.pagesMaxPerDoc": "Max. pagina's / document", - "pricing.comparison.maxFileSize": "Max. bestandsgrootte", - "pricing.comparison.googleTranslation": "Google Vertalen", - "pricing.comparison.deepl": "DeepL", - "pricing.comparison.aiEssential": "AI-basisvertaling", - "pricing.comparison.aiPremium": "AI-premiumvertaling", - "pricing.comparison.apiAccess": "API-toegang", - "pricing.comparison.priorityProcessing": "Prioriteitsverwerking", - "pricing.comparison.support": "Support", - "pricing.comparison.support.community": "Community", - "pricing.comparison.support.email": "E-mail", - "pricing.comparison.support.priority": "Prioriteit", - "pricing.comparison.support.dedicated": "Dedicated", - "pricing.comparison.mb": "MB", - "pricing.credits.title": "Extra tegoeden", - "pricing.credits.subtitle": "Meer nodig? Koop tegoeden per stuk, zonder abonnement.", - "pricing.credits.perPage": "1 tegoed = 1 vertaalde pagina.", - "pricing.credits.bestValue": "Beste waarde", - "pricing.credits.unit": "tegoeden", - "pricing.credits.centsPerCredit": "ct / tegoed", - "pricing.credits.buy": "Kopen", - "pricing.trust.encryption.title": "End-to-end-versleuteling", - "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 at-rest", - "pricing.trust.languages.title": "130+ talen", - "pricing.trust.languages.sub": "Inclusief Arabisch, Perzisch, Hebreeuws (RTL)", - "pricing.trust.parallel.title": "Parallelle verwerking", - "pricing.trust.parallel.sub": "Ultrasnelle multi-threaded AI", - "pricing.trust.availability.title": "24/7 beschikbaar", - "pricing.trust.availability.sub": "99,9 % gegarandeerde beschikbaarheid", - "pricing.aiModels.title": "Onze AI-modellen — maart 2026", - "pricing.aiModels.essential.title": "AI-basisvertaling", - "pricing.aiModels.essential.plan": "Pro-abonnement", - "pricing.aiModels.essential.descPrefix": "Gebaseerd op", - "pricing.aiModels.essential.descSuffix": "— het meest kostenefficiënte AI-model van 2026. Kwaliteit vergelijkbaar met frontier-modellen voor een fractie van de kosten.", - "pricing.aiModels.essential.modelName": "ons Essential AI-model", - "pricing.aiModels.essential.context": "163K tokens context", - "pricing.aiModels.essential.value": "Uitstekende prijs-kwaliteitverhouding", - "pricing.aiModels.premium.title": "AI-premiumvertaling", - "pricing.aiModels.premium.plan": "Business-abonnement", - "pricing.aiModels.premium.descPrefix": "Gebaseerd op", - "pricing.aiModels.premium.descSuffix": "van Anthropic — nauwkeurig bij juridische, medische en complexe technische documenten.", - "pricing.aiModels.premium.context": "200K tokens context", - "pricing.aiModels.premium.precision": "Beste nauwkeurigheid", - "pricing.faq.title": "Veelgestelde vragen", - "pricing.faq.q1": "Kan ik op elk moment van abonnement wisselen?", - "pricing.faq.a1": "Ja. Upgraden gebeurt direct en naar rato. Downgraden gaat in aan het einde van de lopende periode.", - "pricing.faq.q2": "Wat is «AI-basisvertaling»?", - "pricing.faq.a2": "Het is onze IA-engine. Hij begrijpt de context van uw documenten, behoudt de lay-out en behandelt technische termen veel beter dan klassieke vertaling.", - "pricing.faq.q3": "Wat is het verschil tussen Basis- en Premium-AI?", - "pricing.faq.a3": "Essential IA gebruikt een geoptimaliseerd model (uitstekende prijs-kwaliteitverhouding). Premium IA gebruikt Claude 3.5 Haiku van Anthropic, nauwkeuriger bij juridische, medische en complexe technische documenten.", - "pricing.faq.q4": "Worden mijn documenten bewaard na vertaling?", - "pricing.faq.a4": "Vertaalde bestanden zijn beschikbaar volgens uw abonnement (30 dagen Starter, 90 dagen Pro, 1 jaar Business). Ze zijn versleuteld at-rest en in transit.", - "pricing.faq.q5": "Wat gebeurt er als ik mijn maandelijkse quotum overschrijd?", - "pricing.faq.a5": "U kunt extra tegoeden per stuk kopen of uw abonnement upgraden. U wordt op de hoogte gesteld bij 80 % gebruik.", - "pricing.faq.q6": "Is er een gratis proefperiode voor betaalde abonnementen?", - "pricing.faq.a6": "Het Gratis abonnement is permanent en vereist geen creditcard. Voor Pro en Business kunt u ons contacteren voor een proefperiode van 14 dagen.", - "pricing.faq.q7": "Welke bestandsformaten worden ondersteund?", - "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx) en binnenkort PDF. Alle abonnementen ondersteunen dezelfde formaten.", - "pricing.cta.title": "Klaar om te beginnen?", - "pricing.cta.subtitle": "Start gratis, zonder creditcard. Upgrade wanneer u wilt.", - "pricing.cta.createAccount": "Gratis account aanmaken", - "pricing.cta.login": "Inloggen", - "pricing.toast.demo": "Demomodus — Stripe is nog niet geconfigureerd. In productie zou u worden doorgestuurd naar betaling om het {planId}-abonnement te activeren.", - "pricing.toast.networkError": "Netwerkfout. Probeer het opnieuw.", - "pricing.toast.paymentError": "Fout bij aanmaken van de betaling.", - "register.title": "Account aanmaken", - "register.subtitle": "Begin gratis met vertalen", - "register.error.failed": "Registratie mislukt", - "register.name.label": "Naam", - "register.name.placeholder": "Uw naam", - "register.name.error": "De naam moet minimaal 2 tekens bevatten", - "register.email.label": "E-mailadres", - "register.email.placeholder": "u@voorbeeld.nl", - "register.email.error": "Ongeldig e-mailadres", - "register.password.label": "Wachtwoord", - "register.password.error": "Het wachtwoord moet minimaal 8 tekens bevatten, met een hoofdletter, een kleine letter en een cijfer", - "register.password.show": "Wachtwoord tonen", - "register.password.hide": "Wachtwoord verbergen", - "register.password.strengthLabel": "Sterkte:", - "register.password.strength.weak": "Zwak", - "register.password.strength.medium": "Gemiddeld", - "register.password.strength.strong": "Sterk", - "register.confirmPassword.label": "Wachtwoord bevestigen", - "register.confirmPassword.error": "Wachtwoorden komen niet overeen", - "register.confirmPassword.show": "Tonen", - "register.confirmPassword.hide": "Verbergen", - "register.submit.creating": "Account wordt aangemaakt...", - "register.submit.create": "Mijn account aanmaken", - "register.hasAccount": "Al een account?", - "register.login": "Inloggen", - "register.terms.prefix": "Door een account aan te maken, accepteert u onze", - "register.terms.link": "gebruiksvoorwaarden", - "login.errorTitle": "Login Error", - "login.welcomeBack": "Welcome back", - "login.signInToContinue": "Sign in to continue translating", - "login.email": "Email", - "login.emailPlaceholder": "you@example.com", - "login.password": "Password", - "login.forgotPassword": "Forgot password?", - "login.passwordPlaceholder": "••••••••", - "login.signingIn": "Signing in...", - "login.signIn": "Sign In", - "login.noAccount": "Don't have an account?", - "login.signUpFree": "Sign up for free", - "login.orContinueWith": "of ga verder met e-mail", - "login.google.connecting": "Verbinden…", - "login.google.errorGeneric": "Er is iets misgegaan met Google-aanmelding.", - "login.google.errorFailed": "Google-aanmelding mislukt. Probeer het opnieuw.", - "forgotPassword.enterEmail": "Please enter your email address", - "forgotPassword.error": "An error occurred", - "forgotPassword.title": "Forgot Password", - "forgotPassword.checkEmail": "Check your inbox", - "forgotPassword.subtitle": "Enter your email to receive a reset link", - "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", - "forgotPassword.emailLabel": "Email address", - "forgotPassword.emailPlaceholder": "you@example.com", - "forgotPassword.sending": "Sending...", - "forgotPassword.sendLink": "Send reset link", - "forgotPassword.backToLogin": "Back to login", - "forgotPassword.loading": "Loading...", - "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", - "resetPassword.passwordMismatch": "Passwords do not match", - "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", - "resetPassword.error": "An error occurred", - "resetPassword.invalidLink": "Invalid link", - "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", - "resetPassword.requestNewLink": "Request new link", - "resetPassword.successTitle": "Password reset", - "resetPassword.newPasswordTitle": "New password", - "resetPassword.successSubtitle": "You will be redirected to login", - "resetPassword.subtitle": "Set your new password", - "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", - "resetPassword.newPassword": "New password", - "resetPassword.showPassword": "Show password", - "resetPassword.hidePassword": "Hide password", - "resetPassword.confirmPassword": "Confirm password", - "resetPassword.resetting": "Resetting...", - "resetPassword.resetPassword": "Reset password", - "resetPassword.backToLogin": "Back to login", - "resetPassword.loading": "Loading...", - "common.loading": "Laden...", - "profile.header.title": "Mijn profiel", - "profile.header.subtitle": "Beheer je account en voorkeuren.", - "profile.tabs.account": "Account", - "profile.tabs.subscription": "Abonnement", - "profile.tabs.preferences": "Voorkeuren", - "profile.account.user": "Gebruiker", - "profile.account.memberSince": "Lid sinds", - "profile.plan.label": "Abonnement", - "profile.plan.free": "Free", - "profile.plan.starter": "Starter", - "profile.plan.pro": "Pro", - "profile.plan.business": "Business", - "profile.plan.enterprise": "Enterprise", - "profile.plan.pricePerMonth": "{price} €/maand", - "profile.subscription.canceling": "Wordt geannuleerd", - "profile.subscription.active": "Actief", - "profile.subscription.unknown": "Onbekend", - "profile.subscription.accessUntil": "Toegang tot", - "profile.subscription.renewalOn": "Verlenging op", - "profile.subscription.upgradePlan": "Upgrade naar een betaald abonnement", - "profile.subscription.changePlan": "Abonnement wijzigen", - "profile.subscription.manageBilling": "Facturatie beheren", - "profile.subscription.billingUnavailable": "Facturatieportaal niet beschikbaar.", - "profile.subscription.billingError": "Fout bij toegang tot facturatieportaal.", - "profile.subscription.cancelSuccess": "Abonnement geannuleerd. Je behoudt toegang tot het einde van de periode.", - "profile.subscription.cancelError": "Fout bij annulering.", - "profile.subscription.networkError": "Netwerkfout.", - "profile.usage.title": "Gebruik deze maand", - "profile.usage.resetOn": "Reset op", - "profile.usage.documents": "Documenten", - "profile.usage.pages": "Pagina's", - "profile.usage.extraCredits": "extra tegoed", - "profile.usage.extraCreditsPlural": "extra tegoeden", - "profile.usage.quotaReached": "Quota bereikt", - "profile.usage.quotaReachedDesc": "Upgrade naar een hoger abonnement om door te gaan.", - "profile.usage.unlockMore": "Ontgrendel meer vertalingen met een betaald abonnement.", - "profile.usage.viewPlans": "Abonnementen bekijken", - "profile.usage.includedInPlan": "Inbegrepen in je abonnement", - "profile.danger.title": "Gevaarzone", - "profile.danger.description": "Annulering wordt van kracht aan het einde van je huidige periode. Je behoudt toegang tot die datum.", - "profile.danger.confirm": "Weet je het zeker? Deze actie kan niet ongedaan worden gemaakt.", - "profile.danger.confirmCancel": "Annulering bevestigen", - "profile.danger.cancelSubscription": "Mijn abonnement annuleren", - "profile.danger.keep": "Nee, behouden", - "profile.prefs.interfaceLang": "Interfacetaal", - "profile.prefs.interfaceLangDesc": "De taal wordt automatisch gedetecteerd op basis van je browser. Je kunt deze handmatig wijzigen.", - "profile.prefs.defaultTargetLang": "Standaarddoeltaal", - "profile.prefs.selectLanguage": "Selecteer een taal", - "profile.prefs.defaultTargetLangDesc": "Deze taal wordt vooraf geselecteerd voor je vertalingen.", - "profile.prefs.save": "Opslaan", - "profile.prefs.theme": "Thema", - "profile.prefs.themeDesc": "Kies het uiterlijk van de interface", - "profile.prefs.cache": "Cache", - "profile.prefs.cacheDesc": "Het wissen van de lokale cache kan sommige weergaveproblemen oplossen.", - "profile.prefs.clearing": "Wissen...", - "profile.prefs.clearCache": "Cache wissen", - "settings.title": "Instellingen", - "settings.subtitle": "Algemene toepassingsconfiguratie", - "settings.formats.title": "Ondersteunde formaten", - "settings.formats.subtitle": "Documenttypen die je kunt vertalen", - "settings.formats.formulas": "Formules", - "settings.formats.styles": "Stijlen", - "settings.formats.images": "Afbeeldingen", - "settings.formats.headers": "Koppen", - "settings.formats.tables": "Tabellen", - "settings.formats.slides": "Dia's", - "settings.formats.notes": "Notities", - "settings.cache.title": "Cache", - "settings.cache.desc": "Het wissen van de lokale cache kan sommige weergaveproblemen oplossen.", - "settings.cache.clearing": "Wissen...", - "settings.cache.clear": "Cache wissen", - "services.title": "Vertaalaanbieders", - "services.subtitle": "Aanbieders worden geconfigureerd door de beheerder. Je kunt zien welke momenteel beschikbaar zijn voor je account.", - "services.loading": "Aanbieders laden...", - "services.noProviders": "Er zijn momenteel geen aanbieders geconfigureerd. Neem contact op met je beheerder.", - "services.classic": "Klassieke vertaling", - "services.llmPro": "LLM · Contextbewust (Pro)", - "services.available": "Beschikbaar", - "services.model": "Model", - "services.adminOnly.title": "Aanbiederconfiguratie is alleen voor beheerders", - "services.adminOnly.desc": "API-sleutels, modelselectie en aanbiederactivering worden uitsluitend beheerd door de beheerder in het adminpaneel. Je hoeft nooit een API-sleutel in te voeren.", - "apiKeys.title": "API-sleutels", - "apiKeys.subtitle": "Beheer je API-sleutels voor programmatische toegang tot de vertaal-API.", - "apiKeys.loading": "Laden...", - "apiKeys.sectionTitle": "API en automatisering", - "apiKeys.sectionDesc": "Genereer en beheer je API-sleutels voor automatiseringsworkflows", - "apiKeys.keysUsed": "{total} van {max} sleutels gebruikt", - "apiKeys.maxReached": "Maximum aantal sleutels bereikt. Trek een sleutel in om een nieuwe te genereren.", - "apiKeys.canGenerate": "Je kunt nog {count} sleutel genereren", - "apiKeys.canGeneratePlural": "Je kunt nog {count} sleutels genereren", - "apiKeys.generateNew": "Nieuwe sleutel genereren", - "apiKeys.keyRevoked": "Sleutel ingetrokken", - "apiKeys.keyRevokedDesc": "De API-sleutel is succesvol ingetrokken.", - "apiKeys.keyNotFound": "Sleutel niet gevonden", - "apiKeys.keyNotFoundDesc": "De API-sleutel bestaat niet meer. Deze is mogelijk al ingetrokken.", - "apiKeys.error": "Fout", - "apiKeys.revokeError": "Kon de API-sleutel niet intrekken. Probeer opnieuw.", - "apiKeys.limitReached": "Limiet bereikt", - "apiKeys.limitReachedDesc": "Je hebt het maximum van 10 API-sleutels bereikt. Trek een bestaande sleutel in om een nieuwe te genereren.", - "apiKeys.proRequired": "Pro-functie vereist", - "apiKeys.proRequiredDesc": "API-sleutels zijn een Pro-functie. Upgrade je account.", - "apiKeys.generateError": "Kon API-sleutel niet genereren. Probeer opnieuw.", - "apiKeys.upgrade.title": "API-sleutels", - "apiKeys.upgrade.subtitle": "Automatiseer je vertalingen met API-toegang", - "apiKeys.upgrade.feat1": "Genereer onbeperkt API-sleutels", - "apiKeys.upgrade.feat2": "Automatiseer documentvertaling", - "apiKeys.upgrade.feat3": "Webhook-meldingen", - "apiKeys.upgrade.feat4": "LLM-vertaalmodi", - "apiKeys.upgrade.proFeature": "API-sleutels zijn een {pro}-functie. Upgrade om API-automatisering te ontgrendelen.", - "apiKeys.upgrade.pro": "Pro", - "apiKeys.upgrade.cta": "Upgrade naar Pro", - "apiKeys.dialog.maxTitle": "Maximum aantal sleutels bereikt", - "apiKeys.dialog.maxDesc": "Je hebt het maximum van 10 API-sleutels bereikt. Trek een bestaande sleutel in voordat je een nieuwe genereert.", - "apiKeys.dialog.close": "Sluiten", - "apiKeys.dialog.generated": "API-sleutel gegenereerd!", - "apiKeys.dialog.generatedDesc": "Je nieuwe API-sleutel is aangemaakt. Kopieer hem nu - hij wordt niet meer getoond.", - "apiKeys.dialog.important": "Belangrijk:", - "apiKeys.dialog.importantDesc": "Dit is de enige keer dat je deze sleutel ziet. Bewaar hem veilig.", - "apiKeys.dialog.apiKey": "API-sleutel", - "apiKeys.dialog.name": "Naam:", - "apiKeys.dialog.done": "Klaar", - "apiKeys.dialog.copied": "Ik heb de sleutel gekopieerd", - "apiKeys.dialog.generateTitle": "Nieuwe API-sleutel genereren", - "apiKeys.dialog.generateDesc": "Maak een nieuwe API-sleutel aan voor programmatische toegang tot de vertaal-API.", - "apiKeys.dialog.keyName": "Sleutelnaam (optioneel)", - "apiKeys.dialog.keyNamePlaceholder": "bijv. Productie, Staging", - "apiKeys.dialog.keyNameHint": "Een beschrijvende naam om deze sleutel later te herkennen.", - "apiKeys.dialog.nameTooLong": "Naam mag maximaal {max} tekens bevatten", - "apiKeys.dialog.nameInvalid": "Naam mag alleen letters, cijfers, spaties, koppeltekens en underscores bevatten", - "apiKeys.dialog.cancel": "Annuleren", - "apiKeys.dialog.generating": "Genereren...", - "apiKeys.dialog.generate": "Sleutel genereren", - "apiKeys.table.name": "Naam", - "apiKeys.table.prefix": "Voorvoegsel", - "apiKeys.table.created": "Aangemaakt", - "apiKeys.table.lastUsed": "Laatst gebruikt", - "apiKeys.table.never": "Nooit", - "apiKeys.table.actions": "Acties", - "apiKeys.table.revoke": "Intrekken", - "apiKeys.table.copyPrefix": "Sleutelvoorvoegsel kopiëren", - "apiKeys.table.revokeKey": "Sleutel intrekken", - "apiKeys.revokeDialog.title": "API-sleutel intrekken", - "apiKeys.revokeDialog.desc": "Weet je zeker dat je de sleutel \"{name}\" wilt intrekken? Deze actie kan niet ongedaan worden gemaakt.", - "apiKeys.revokeDialog.confirm": "Ja, intrekken", - "apiKeys.revokeDialog.cancel": "Annuleren", - "context.proTitle": "Pro-functie", - "context.proDesc": "Context en professionele woordenlijsten zijn beschikbaar met Pro-, Business- en Enterprise-abonnementen. Ze bieden nauwkeurigere vertalingen via instructies en vocabulair specifiek voor jouw domein.", - "context.viewPlans": "Abonnementen bekijken", - "context.title": "Context en woordenlijst", - "context.subtitle": "Verbeter de vertaalkwaliteit met instructies en vocabulair specifiek voor jouw domein.", - "context.presets.title": "Professionele woordenlijsten", - "context.presets.desc": "Laad een volledige woordenlijst met instructies en gespecialiseerde terminologie", - "context.instructions.title": "Contextinstructies", - "context.instructions.desc": "Instructies die de AI volgt tijdens het vertalen", - "context.instructions.placeholder": "Bijv.: Je vertaalt HVAC-technische documenten. Gebruik nauwkeurige technische terminologie...", - "context.glossary.title": "Technische woordenlijst", - "context.glossary.desc": "Formaat: bron=doel (één per regel). Woordenlijsten geladen via preset zijn bewerkbaar.", - "context.glossary.terms": "termen in de woordenlijst", - "context.clearAll": "Alles wissen", - "context.saving": "Opslaan...", - "context.save": "Opslaan", - "translate.glossary.title": "Woordenlijst", - "translate.glossary.select": "Woordenlijst selecteren", - "translate.glossary.none": "Geen", - "translate.glossary.terms": "termen", - "translate.glossary.proOnly": "Upgrade naar Pro voor woordenlijsten", - "translate.glossary.myGlossaries": "Mijn woordenlijsten", - "translate.glossary.fromTemplate": "Van sjabloon maken", - "translate.glossary.noGlossaryForPair": "Geen woordenlijst voor", - "translate.glossary.noGlossaries": "Geen woordenlijsten", - "translate.glossary.loading": "Laden...", - "translate.glossary.classicMode": "Neutrale motor zonder woordenlijst (alleen AI)", - "translate.glossary.selectPlaceholder": "Woordenlijst selecteren...", - "translate.glossary.multilingual": "MEERTALIG", - "translate.glossary.noGlossaryAvailable": "Geen woordenlijst beschikbaar", - "translate.glossary.filterByLang": "Filteren op taal", - "translate.glossary.active": "Actief", - "translate.glossary.inactive": "Inactief", - "translate.glossary.availableTemplates": "Beschikbare sjablonen", - "translate.glossary.importing": "Bezig met importeren...", - "translate.glossary.imported": "(Geïmporteerd)", - "translate.glossary.noGlossaryForSource": "Geen woordenlijst of sjabloon voor brontaal", - "translate.glossary.createGlossary": "Woordenlijst maken", - "translate.glossary.showAll": "Alle woordenlijsten tonen", - "translate.glossary.activePreview": "Voorbeeld van actieve overeenkomsten:", - "translate.glossary.total": "totaal", - "translate.glossary.moreTerms": "meer termen", - "translate.glossary.noTerms": "Geen termen in deze woordenlijst.", - "translate.glossary.sourceTerm": "Bronterm", - "translate.glossary.translation": "Vertaling", - "translate.glossary.addTerm": "Term toevoegen", - "translate.glossary.disabledMode": "Neutrale motor zonder toegepaste woordenlijst", - "translate.glossary.addTermError": "Fout bij toevoegen van term", - "translate.glossary.networkError": "Netwerkfout", - "translate.glossary.importFailed": "Importeren mislukt ({status})", - "translate.glossary.helpText": "De woordenlijst dwingt nauwkeurige termvertaling af. Kies een woordenlijst waarvan de brontaal overeenkomt met de oorspronkelijke taal van uw document.", - "translate.glossary.sourceWarning": "Let op: Deze woordenlijst gebruikt brontaal", - "translate.glossary.sourceWarningBut": "maar uw document is geconfigureerd in", - "translate.glossary.targetWarning": "Doel incompatibiliteit: Deze woordenlijst is ontworpen om te vertalen naar", - "translate.glossary.targetWarningBut": "maar uw document is gericht op", - "translate.glossary.targetWarningEnd": "De termen zijn mogelijk niet relevant.", - "context.presets.createGlossary": "Woordenlijst maken", - "context.presets.created": "Woordenlijst gemaakt", - "context.presets.createdDesc": "De woordenlijst \"{name}\" is gemaakt met {count} termen.", - "context.presets.hint": "Klik op een preset om een woordenlijst met domeinspecifieke termen te maken. Beheer je woordenlijsten in het Woordenlijsten-gedeelte.", - "context.glossary.manage": "Woordenlijsten beheren", - "context.saved": "Opgeslagen", - "context.savedDesc": "Je contextinstructies zijn opgeslagen.", - "admin.login.title": "Beheer", - "admin.login.required": "Inloggen vereist", - "admin.login.password": "Admin-wachtwoord", - "admin.login.connecting": "Verbinden...", - "admin.login.access": "Toegang tot admin-paneel", - "admin.login.restricted": "Alleen voor beheerders", - "admin.layout.checking": "Authenticatie verifiëren...", - "admin.dashboard.title": "Admin Dashboard", - "admin.dashboard.subtitle": "Beheerder controlepaneel", - "admin.dashboard.refresh": "Vernieuwen", - "admin.dashboard.refreshTooltip": "Dashboard-gegevens vernieuwen", - "admin.dashboard.config": "Systeemconfiguratie", - "admin.dashboard.maxFileSize": "Max bestandsgrootte:", - "admin.dashboard.translationService": "Vertaalservice:", - "admin.dashboard.formats": "Formaten:", - "admin.nav.dashboard": "Dashboard", - "admin.nav.users": "Gebruikers", - "admin.nav.pricing": "Prijzen & Stripe", - "admin.nav.providers": "Providers", - "admin.nav.system": "Systeem", - "admin.nav.logs": "Logboeken", - "admin.users.title": "Gebruikersbeheer", - "admin.users.subtitle": "Gebruikersaccounts bekijken en beheren", - "admin.users.planUpdated": "Abonnement bijgewerkt", - "admin.users.planChanged": "Het abonnement is succesvol gewijzigd naar \"{plan}\".", - "admin.users.unknownError": "Onbekende fout", - "admin.users.error": "Fout", - "admin.users.planUpdateError": "Kan abonnement niet bijwerken: {message}", - "admin.users.noKeys": "Geen sleutels", - "admin.users.noKeysDesc": "Deze gebruiker heeft geen actieve API-sleutels.", - "admin.users.keysRevoked": "Sleutels ingetrokken", - "admin.users.keysRevokedDesc": "{count} API-sleutel(s) succesvol ingetrokken.", - "admin.users.revokeError": "Kan sleutels niet intrekken: {message}", - "admin.users.retry": "Opnieuw proberen", - "admin.system.title": "Systeem", - "admin.system.subtitle": "Systeemstatus bewaken en bronnen beheren", - "admin.system.quotas": "Vertaalquota's", - "admin.system.resetQuotas": "Maandelijkse quota's resetten", - "admin.system.resetting": "Resetten...", - "admin.system.reset": "Resetten", - "admin.system.allOperational": "Alle systemen operationeel", - "admin.system.issuesDetected": "Systeemproblemen gedetecteerd", - "admin.system.waitingData": "Wachten op gegevens...", - "admin.system.purging": "Wissen...", - "admin.system.clean": "Opschonen", - "admin.system.purge": "Wissen", - "memento.title": "Ontdek Momento", - "memento.slogan": "Momento is meer dan alleen een notitie-app. Het is een intelligent ecosysteem dat uw ideeën in realtime verbindt, analyseert en verder ontwikkelt met 6 AI-agents en geavanceerde semantische zoekfuncties.", - "memento.ctaFree": "Gratis beginnen", - "memento.ctaMore": "Meer informatie", - "common.backToHome": "Terug naar home", - "dashboard.topbar.interfaceLabel": "Vertaalinterface", - "dashboard.topbar.premiumAccess": "Premium-toegang", - "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", - "layout.nav.apiAccess": "API-toegang", - "layout.footer.terms": "Voorwaarden", - "layout.footer.privacy": "Privacy", - "fileUploader.uploadDocument": "Document uploaden", - "fileUploader.uploadDesc": "Sleep of klik om een bestand te selecteren (Excel, Word, PowerPoint)", - "fileUploader.dropHere": "Zet uw bestand hier neer…", - "fileUploader.dragAndDrop": "Sleep uw document hierheen", - "fileUploader.orClickBrowse": "of klik om te bladeren", - "fileUploader.preview": "Voorbeeld", - "fileUploader.translationOptions": "Vertaalopties", - "fileUploader.configureSettings": "Vertaalinstellingen configureren", - "fileUploader.targetLanguage": "Doeltaal", - "fileUploader.selectLanguage": "Selecteer taal", - "fileUploader.translationProvider": "Vertaalprovider", - "fileUploader.selectProvider": "Selecteer provider", - "fileUploader.advancedOptions": "Geavanceerde opties", - "fileUploader.translateImages": "Afbeeldingen vertalen", - "fileUploader.translating": "Bezig met vertalen…", - "fileUploader.translateDocument": "Document vertalen", - "fileUploader.processing": "Verwerken…", - "fileUploader.translationError": "Vertaalfout", - "fileUploader.translationComplete": "Vertaling voltooid!", - "fileUploader.translationCompleteDesc": "Uw document is succesvol vertaald met behoud van alle opmaak.", - "fileUploader.download": "Vertaald document downloaden", - "fileUploader.webgpuUnsupported": "WebGPU wordt niet ondersteund in deze browser. Gebruik Chrome 113+ of Edge 113+.", - "fileUploader.webllmNotLoaded": "WebLLM-model niet geladen. Ga naar Instellingen > Vertaaldiensten om een model te laden.", - "fileUploader.extracting": "Teksten uit document extraheren…", - "fileUploader.noTranslatable": "Geen vertaalbare tekst gevonden in document", - "fileUploader.foundTexts": "{count} teksten gevonden om te vertalen", - "fileUploader.translatingItem": "Vertalen {current}/{total}: „{preview}\"", - "fileUploader.reconstructing": "Document reconstrueren…", - "fileUploader.translatingLocally": "Lokaal vertalen met WebLLM…", - "checkout.activating": "Activeren…", - "checkout.activatingDesc": "We werken uw abonnement bij, even geduld.", - "checkout.paymentConfirmed": "Betaling bevestigd!", - "checkout.subscriptionActivated": "Abonnement geactiveerd!", - "checkout.planActivated": "{plan}-abonnement geactiveerd!", - "checkout.redirectingToProfile": "Doorverwijzen naar uw profiel…", - "checkout.paymentReceived": "Betaling ontvangen", - "checkout.redirecting": "Doorverwijzen…", - "checkout.syncError": "Synchronisatiefout", - "checkout.networkError": "Netwerkfout. Uw betaling is bevestigd — vernieuw uw profiel.", - "dashboard.checkoutSyncError": "Fout bij synchroniseren van betaling.", - "dashboard.networkRefresh": "Netwerkfout. Vernieuw de pagina.", - "dashboard.continueToTranslate": "Doorgaan naar vertaling", - "langSelector.search": "Zoeken…", - "langSelector.noResults": "Geen resultaten", - "langSelector.source": "Bron", - "langSelector.target": "Doel", - "langSelector.swap": "Wisselen", - "translateComplete.highQuality": "Hoge kwaliteit", - "translateComplete.segments": "Segmenten", - "translateComplete.characters": "Tekens", - "translateComplete.confidence": "Betrouwbaarheid", - "providerTheme.deepseek.badge": "Essentieel", - "providerTheme.deepseek.subBadge": "Technisch & zuinig", - "providerTheme.deepseek.desc": "Ultraprecieze en zuinige vertaling, ideaal voor technische documenten en code.", - "providerTheme.openai.badge": "Premium", - "providerTheme.openai.subBadge": "Hoge getrouwheid", - "providerTheme.openai.desc": "De wereldwijde AI-standaard. Maximale tekstconsistentie en strikte stijlrespect.", - "providerTheme.minimax.badge": "Geavanceerd", - "providerTheme.minimax.subBadge": "Prestaties", - "providerTheme.minimax.desc": "Ongelofelijke uitvoersnelheid en uitstekend begrip van complexe structuren.", - "providerTheme.openrouter.badge": "Express", - "providerTheme.openrouter.subBadge": "Multi-model", - "providerTheme.openrouter.desc": "Uniforme toegang tot de beste open-source modellen, geoptimaliseerd voor vertaling.", - "providerTheme.openrouter_premium.badge": "Ultra", - "providerTheme.openrouter_premium.subBadge": "Maximale context", - "providerTheme.openrouter_premium.desc": "Ondersteund door state-of-the-art modellen (GPT-4o, Claude Sonnet 4.6) voor lange documenten.", - "providerTheme.zai.badge": "Gespecialiseerd", - "providerTheme.zai.subBadge": "Financiën & Recht", - "providerTheme.zai.desc": "Model afgestemd op veeleisende bedrijfsterminologieën (juridisch, financieel).", - "providerTheme.default.badge": "Modern", - "providerTheme.default.subBadge": "AI-redenering", - "providerTheme.default.desc": "Grote taalmodel (LLM) vertaling met geavanceerde semantische analyse.", - "providerTheme.classic.google.label": "Google Vertalen", - "providerTheme.classic.google.desc": "Ultrasnelle vertaling voor meer dan 130 talen. Aanbevolen voor algemene stromen.", - "providerTheme.classic.deepl.label": "DeepL Pro", - "providerTheme.classic.deepl.desc": "Hoge precisie vertaling, bekend om vloeibaarheid en natuurlijke formuleringen.", - "providerTheme.classic.google_cloud.label": "Google Cloud API", - "providerTheme.classic.google_cloud.desc": "Professionele cloud-engine geoptimaliseerd voor het verwerken van grote documentvolumes.", - "providerSelector.noClassic": "Geen standaard vertaler beschikbaar.", - "providerSelector.noLlm": "Geen AI-model geconfigureerd.", - "providerSelector.costOne": "Kosten: 1 credit per pagina", - "providerSelector.costFive": "Kosten: 5 credits per pagina (Premium-factor)", - "providerSelector.unlockContextual": "Premium contextuele vertaling voor uw volledige documenten ontgrendelen.", - "translate.header.processing": "Verwerking bezig", - "translate.header.aiActive": "AI-analyse actief", - "translate.header.aiActiveDesc": "Uw opmaak wordt behouden door onze contextuele engine.", - "translate.header.completed": "Voltooid", - "translate.header.completedTitle": "Vertaling voltooid", - "translate.header.proSpace": "Pro-ruimte", - "translate.header.translateDoc": "Een document vertalen", - "translate.header.translateDocDesc": "Behoud de originele opmaak met onze ultra-hoge-fidelity vertaalengine.", - "translate.upload.nativeFormat": "Native formaat", - "translate.fileType.word": "Word (.docx)", - "translate.fileType.excel": "Excel (.xlsx)", - "translate.fileType.slides": "Dia's (.pptx)", - "translate.fileType.pdf": "PDF (.pdf)", - "translate.startTranslation": "Vertaling starten", - "translate.submit": "Verzenden…", - "translate.chooseTargetLang": "Kies een doeltaal", - "translate.pleaseLoadFile": "Upload eerst een bestand", - "translate.contextEngineActive": "Contextuele engine actief", - "translate.phase1": "Fase 1: Initialisatie", - "translate.phase2": "Fase 2: Contextuele reconstructie", - "translate.stat.segments": "segmenten", - "translate.stat.precision": "precisie", - "translate.stat.speedLabel": "snelheid", - "translate.stat.turbo": "Turbo", - "translate.stat.time": "tijd", - "translate.complete.masterQuality": "✓ Meesterkwaliteit", - "translate.download": "Downloaden", - "translate.newTranslation": "+ Nieuwe vertaling", - "translate.failedTitle": "Vertaalfout", - "translate.retry": "Opnieuw", - "translate.uploadAnother": "Een ander bestand uploaden", - "translate.monitor": "AI-monitor", - "translate.summary": "Samenvatting", - "translate.cancelProcess": "⟳ Proces annuleren", - "translate.layoutIntegrity": "Lay-out integriteit", - "translate.secureHundred": "100% VEILIG", - "translate.okHundred": "100% OK", - "translate.preserveLayout": "Opmaak behouden", - "translate.preserveLayoutDesc": "Opmaak behouden", - "translate.textOnly": "Alleen tekst", - "translate.textOnlyDesc": "Snelle vertaling van alleen tekst", - "translate.unavailableStandard": "Niet beschikbaar in Standaardmodus (alleen AI)", - "apiKeys.noKeysGenerated": "Geen sleutels gegenereerd", - "apiKeys.copied": "Gekopieerd!", - "services.fallback.google.label": "Google Vertalen", - "services.fallback.google.desc": "Snelle vertaling, 130+ talen", - "settings.formats.excel.name": "Excel", - "settings.formats.word.name": "Word", - "settings.formats.powerpoint.name": "PowerPoint", - "pricing.dashboard": "Dashboard", - "pricing.okSymbol": "✓", - "pricing.errSymbol": "✕", - }, - // ═══════════════════════════════════════════════════════════════ - // RUSSIAN (ru) - // ═══════════════════════════════════════════════════════════════ - ru: { - "auth.brandName": "Wordly", - "dashboard.nav.translate": "Перевести", - "dashboard.nav.profile": "Мой профиль", - "dashboard.nav.settings": "Настройки", - "dashboard.nav.context": "Контекст", - "dashboard.nav.services": "Сервисы", - "dashboard.nav.apiKeys": "API-ключи", - "dashboard.nav.glossaries": "Глоссарии", - "dashboard.header.title": "Панель управления", - "dashboard.header.subtitle": "Управляйте своими переводами", - "dashboard.header.toggleMenu": "Меню", - "dashboard.header.profileTitle": "Мой профиль", - "dashboard.sidebar.theme": "Тема", - "dashboard.sidebar.signOut": "Выйти", - "dashboard.sidebar.backHome": "Вернуться на главную", - "dashboard.sidebar.upgradeToPro": "Обновить до Pro →", - "cookieConsent.title": "Файлы cookie в Wordly", - "cookieConsent.description": "Мы используем essential файлы cookie для работы приложения (сессия, безопасность, язык). С вашего разрешения мы также используем необязательные файлы cookie для измерения трафика и улучшения продукта.", - "cookieConsent.acceptAll": "Принять все", - "cookieConsent.essentialOnly": "Только необходимые", - "cookieConsent.learnMore": "Подробнее", - "landing.nav.why": "Почему мы?", - "landing.nav.formats": "Форматы", - "landing.nav.pricing": "Цены", - "landing.nav.login": "Войти", - "landing.nav.startFree": "Бесплатно", - "landing.hero.tag": "Профессиональный документальный ИИ", - "landing.hero.titleLine1": "Переводите документы.", - "landing.hero.titleLine2": "С идеальным форматированием.", - "landing.hero.description": "Единственный переводчик, который сохраняет SmartArt, диаграммы, оглавления, фигуры и сложные макеты — в точности как в оригинале.", - "landing.hero.ctaMain": "Бесплатно — 2 док./мес.", - "landing.hero.ctaSec": "Смотреть тарифы", - "landing.hero.deleted": "Файлы удаляются через 60 мин.", - "landing.hero.noHidden": "Без скрытых платежей", - "landing.hero.preview": "Предпросмотр перед оплатой", - "landing.hero.formattedOk": "Форматирование ОК", - "landing.hero.aiActive": "ИИ-перевод активен", - "landing.steps.title": "Как это работает?", - "landing.steps.subtitle": "Три шага. Нулевая потеря форматирования.", - "landing.steps.step1.num": "01", - "landing.steps.step1.title": "Загрузите файл", - "landing.steps.step1.desc": "Перетащите документ Excel, Word, PowerPoint или PDF.", - "landing.steps.step2.num": "02", - "landing.steps.step2.title": "Выберите язык и движок", - "landing.steps.step2.desc": "Выберите целевой язык и движок — классический или контекстный ИИ.", - "landing.steps.step3.num": "03", - "landing.steps.step3.title": "Скачайте результат", - "landing.steps.step3.desc": "Получите переведённый документ с форматированием, идентичным оригиналу.", - "landing.features.tag": "Движок ИИ-перевода", - "landing.features.title": "Перевод, который понимает вашу сферу", - "landing.features.description": "Наши ИИ-модели анализируют контекст, уважают вашу терминологию и даже переводят текст внутри изображений.", - "landing.features.context.title": "Отраслевой контекст", - "landing.features.context.desc": "Опишите свою отрасль и получите адаптированный перевод, а не универсальный.", - "landing.features.glossary.title": "Отраслевые глоссарии", - "landing.features.glossary.desc": "Определите свои технические термины. CTA останется «Воздухообрабатывающая установка», а не «Призыв к действию».", - "landing.features.vision.title": "Распознавание изображений", - "landing.features.vision.desc": "Текст, встроенный в изображения, диаграммы и графики, распознаётся и переводится.", - "landing.features.demo.source": "Исходник (FR)", - "landing.features.demo.google": "Google Translate", - "landing.features.demo.ours": "Наш ИИ", - "landing.layout.title": "Ваше форматирование,", - "landing.layout.title2": "идеально сохранено", - "landing.layout.subtitle": "Другие переводчики ломают макет. Мы — нет.", - "landing.layout.p1.title": "SmartArt и диаграммы", - "landing.layout.p1.desc": "Органограммы, блок-схемы, иерархии — всё переведено идентично.", - "landing.layout.p2.title": "Оглавления", - "landing.layout.p2.desc": "Записи оглавления, номера страниц и перекрёстные ссылки обновлены корректно.", - "landing.layout.p3.title": "Диаграммы и графики", - "landing.layout.p3.desc": "Заголовки, подписи осей, легенды и названия серий — всё переведено.", - "landing.layout.p4.title": "Фигуры и текстовые поля", - "landing.layout.p4.desc": "Прямоугольники, скруглённые блоки, выноски — локализованы повсюду.", - "landing.layout.p5.title": "Колонтитулы", - "landing.layout.p5.desc": "Верхние и нижние колонтитулы, а также сноски никогда не пропускаются.", - "landing.layout.p6.title": "130+ языков", - "landing.layout.p6.desc": "Google Переводчик, DeepL и профессиональные ИИ-движки.", - "landing.formats.title": "Любой формат,", - "landing.formats.title2": "любой элемент", - "landing.formats.subtitle": "Мы переводим то, что другие пропускают. Ваш бизнес заслуживает безупречной документации.", - "landing.formats.word.name": "Word", - "landing.formats.word.i1": "Абзацы и заголовки", - "landing.formats.word.i2": "Таблицы и диаграммы", - "landing.formats.word.i3": "Диаграммы SmartArt", - "landing.formats.word.i4": "Оглавление", - "landing.formats.word.i5": "Колонтитулы", - "landing.formats.word.i6": "Фигуры и текстовые поля", - "landing.formats.word.i7": "Сноски и концевые сноски", - "landing.formats.excel.name": "Excel", - "landing.formats.excel.i1": "Значения ячеек", - "landing.formats.excel.i2": "Имена листов", - "landing.formats.excel.i3": "Диаграммы и подписи", - "landing.formats.excel.i4": "Колонтитулы", - "landing.formats.excel.i5": "Объединённые ячейки сохранены", - "landing.formats.pptx.name": "PowerPoint", - "landing.formats.pptx.i1": "Текст слайдов и заметки", - "landing.formats.pptx.i2": "Диаграммы и графики", - "landing.formats.pptx.i3": "Фигуры и текстовые поля", - "landing.formats.pptx.i4": "Макеты образцов", - "landing.formats.pptx.i5": "Анимации сохранены", - "landing.formats.pdf.name": "PDF", - "landing.formats.pdf.i1": "Текстовые PDF", - "landing.formats.pdf.i2": "Макет сохранён", - "landing.formats.pdf.i3": "Изображения на месте", - "landing.formats.pdf.i4": "Таблицы сохранены", - "landing.formats.pdf.i5": "Результат в DOCX или PDF", - "landing.pricing.title": "Простые и честные цены", - "landing.pricing.subtitle": "Что видите — то и платите. Без скрытых платежей.", - "landing.pricing.monthly": "Ежемесячно", - "landing.pricing.annual": "Ежегодно", - "landing.pricing.bestValue": "Самый популярный", - "landing.pricing.month": "/мес.", - "landing.pricing.footer": "Указанная цена — это цена, которую вы платите. Никаких скрытых платежей после перевода.", - "landing.pricing.starter.name": "Starter", - "landing.pricing.starter.desc": "Для частных лиц и небольших проектов", - "landing.pricing.starter.f1": "50 документов / мес.", - "landing.pricing.starter.f2": "До 50 страниц на документ", - "landing.pricing.starter.f3": "Google Переводчик + DeepL", - "landing.pricing.starter.f4": "Файлы до 10 МБ", - "landing.pricing.starter.cta": "Начать", - "landing.pricing.pro.name": "Pro", - "landing.pricing.pro.desc": "Для требовательных профессионалов", - "landing.pricing.pro.f1": "200 документов / мес.", - "landing.pricing.pro.f2": "До 200 страниц на документ", - "landing.pricing.pro.f3": "Перевод на базе ИИ", - "landing.pricing.pro.f4": "Google + DeepL включены", - "landing.pricing.pro.f5": "Пользовательские глоссарии и промпты", - "landing.pricing.pro.f6": "Приоритетная поддержка", - "landing.pricing.pro.cta": "Попробовать Pro", - "landing.pricing.business.name": "Бизнес", - "landing.pricing.business.desc": "Для команд с большими объёмами", - "landing.pricing.business.f1": "1 000 документов / мес.", - "landing.pricing.business.f2": "До 500 страниц на документ", - "landing.pricing.business.f3": "Премиум ИИ (Claude)", - "landing.pricing.business.f4": "Все провайдеры + API", - "landing.pricing.business.f5": "Вебхуки и автоматизация", - "landing.pricing.business.f6": "5 рабочих мест", - "landing.pricing.business.cta": "Связаться с нами", - "landing.cta.title": "Начните переводить за 30 секунд", - "landing.cta.subtitle": "Кредитная карта не требуется. Попробуйте бесплатно прямо сейчас и верните к жизни ваши многоязычные документы.", - "landing.cta.button": "Создать бесплатный аккаунт", - "landing.cta.secure": "Защищено шифрованием AES-256", - "landing.footer.desc": "Эксперт в интеллектуальном переводе документов. Мы сочетаем искусство вёрстки с наукой контекстного ИИ.", - "landing.footer.product": "Продукт", - "landing.footer.resources": "Ресурсы", - "landing.footer.legal": "Правовая информация", - "landing.footer.rights": "© 2026 Wordly.art — Все права защищены.", - "dashboard.translate.pageTitle": "Перевести документ", - "dashboard.translate.pageSubtitle": "Импортируйте файл и выберите целевой язык", - "dashboard.translate.errorNotificationTitle": "Ошибка", - "dashboard.translate.dropzone.uploadAria": "Зона перетаскивания файлов", - "dashboard.translate.dropzone.title": "Перетащите файл сюда", - "dashboard.translate.dropzone.subtitle": "или нажмите, чтобы выбрать (DOCX, XLSX, PPTX, PDF)", - "dashboard.translate.dropzone.replaceFile": "Заменить файл", - "dashboard.translate.language.source": "Исходный язык", - "dashboard.translate.language.target": "Целевой язык", - "dashboard.translate.language.loading": "Загрузка языков…", - "dashboard.translate.language.autoDetect": "Автоопределение", - "dashboard.translate.language.selectPlaceholder": "Выбрать…", - "dashboard.translate.language.loadErrorPrefix": "Ошибка загрузки языков", - "dashboard.translate.provider.loading": "Загрузка провайдеров…", - "dashboard.translate.provider.noneConfigured": "Провайдеры не настроены", - "dashboard.translate.provider.modelTitle": "Модель", - "dashboard.translate.provider.sectionTitle": "Провайдер", - "dashboard.translate.provider.llmDivider": "ИИ · Контекстный", - "dashboard.translate.provider.llmDividerPro": "ИИ · Контекстный (Pro)", - "dashboard.translate.provider.upgrade": "Обновить до Pro", - "dashboard.translate.provider.upgradeSuffix": "чтобы разблокировать ИИ-перевод", - "dashboard.translate.trust.zeroRetention": "Без хранения", - "dashboard.translate.trust.deletedAfter": "Файлы удаляются после обработки", - "dashboard.translate.actions.uploading": "Загрузка…", - "dashboard.translate.actions.translate": "Перевести", - "dashboard.translate.actions.filePrefix": "Файл: ", - "dashboard.translate.actions.cancel": "Отмена", - "dashboard.translate.actions.tryAgain": "Повторить", - "dashboard.translate.steps.uploading": "Загрузка файла…", - "dashboard.translate.steps.starting": "Запуск перевода…", - "dashboard.translate.complete.title": "Перевод завершён!", - "dashboard.translate.complete.descNamed": "Ваш файл {name} успешно переведён.", - "dashboard.translate.complete.descGeneric": "Ваш файл успешно переведён.", - "dashboard.translate.complete.downloading": "Скачивание…", - "dashboard.translate.complete.download": "Скачать", - "dashboard.translate.complete.newTranslation": "Новый перевод", - "dashboard.translate.complete.toastOkTitle": "Успешно", - "dashboard.translate.complete.toastOkDesc": "{name} успешно загружен.", - "dashboard.translate.complete.toastFailTitle": "Ошибка", - "dashboard.translate.complete.toastFailDesc": "Перевод не удался. Пожалуйста, попробуйте снова.", - "dashboard.translate.sourceDocument": "Исходный документ", - "dashboard.translate.configuration": "Настройки", - "dashboard.translate.translating": "Перевод выполняется", - "dashboard.translate.liveMonitor": "Мониторинг", - "dashboard.translate.summary": "Сводка", - "dashboard.translate.engine": "Движок", - "dashboard.translate.confidence": "Достоверность", - "dashboard.translate.cancel": "Отмена", - "dashboard.translate.segments": "Сегменты", - "dashboard.translate.characters": "Символы", - "dashboard.translate.elapsed": "Прошло", - "dashboard.translate.segPerMin": "Сег/мин", - "dashboard.translate.highQuality": "Высокое качество", - "dashboard.translate.quality": "Качество", - "dashboard.translate.completed": "Перевод завершён", - "dashboard.translate.replace": "Заменить", - "dashboard.translate.pdfMode.title": "Режим перевода PDF", - "dashboard.translate.pdfMode.preserveLayout": "Сохранить вёрстку", - "dashboard.translate.pdfMode.textOnly": "Только текст", - "dashboard.translate.pdfMode.preserveLayoutDesc": "Сохраняет изображения, таблицы и форматирование. Лучше для простых PDF.", - "dashboard.translate.pdfMode.textOnlyDesc": "Идеальный перевод всего текста. Чистый результат без проблем с вёрсткой.", - "dashboard.translate.pipeline.upload": "Загрузка", - "dashboard.translate.pipeline.analyze": "Анализ", - "dashboard.translate.pipeline.translate": "Перевод", - "dashboard.translate.pipeline.rebuild": "Восстановление", - "dashboard.translate.pipeline.finalize": "Завершение", - "dashboard.translate.progress.processingFallback": "Обработка…", - "dashboard.translate.progress.connectionLost": "Соединение потеряно. Повторная попытка…", - "dashboard.translate.progress.failedTitle": "Перевод не удался", - "dashboard.translate.error.unexpected": "Произошла непредвиденная ошибка. Попробуйте снова.", - "dashboard.translate.error.noResult": "Перевод не дал результатов. Убедитесь, что документ содержит текст, и попробуйте снова или выберите другой движок.", - "dashboard.translate.error.apiKey": "Недействительный или отсутствующий API-ключ. Обратитесь к администратору для настройки ключей.", - "dashboard.translate.error.quota": "Лимит использования достигнут. Попробуйте снова через несколько минут или выберите другой движок.", - "dashboard.translate.error.timeout": "Время соединения с сервисом перевода истекло. Проверьте сеть и попробуйте снова.", - "dashboard.translate.error.sessionExpired": "Сессия истекла. Нажмите «Повторить» для перезапуска перевода.", - "dashboard.translate.error.empty": "Документ пуст или не содержит переводимого текста (сканированный PDF?).", - "dashboard.translate.error.unsupported": "Неподдерживаемый формат файла или повреждённый файл.", - "dashboard.translate.error.connection": "Соединение потеряно. Проверьте сеть и попробуйте снова.", - "dashboard.translate.error.generic": "Перевод не удался: {detail}", - "dashboard.translate.error.title": "Перевод не удался", - "dashboard.translate.retry": "Повторить перевод", - "dashboard.translate.newFile": "Новый файл", - "dashboard.translate.modeAI": "Режим ИИ", - "dashboard.translate.modeClassic": "Классический режим", - "dashboard.translate.glossaryLLMHint": "Глоссарии доступны в режиме ИИ", - "dashboard.translate.submitting": "Отправка...", - "dashboard.translate.submit": "Начать перевод", - "dashboard.translate.noFile": "Сначала загрузите файл", - "dashboard.translate.noTargetLang": "Выберите целевой язык", - "glossaries.yourGlossaries": "Ваши глоссарии", - "glossaries.title": "Глоссарии и контекст", - "glossaries.description": "Управляйте глоссариями и контекстными инструкциями для более точных переводов.", - "glossaries.createNew": "Создать новый", - "glossaries.empty": "Глоссариев пока нет", - "glossaries.emptyDesc": "Создайте первый глоссарий или загрузите профессиональный пресет выше", - "glossaries.defineTerms": "терминов", - "glossaries.aboutTitle": "О глоссариях", - "glossaries.aboutDesc": "Глоссарии позволяют определить точные переводы для конкретных терминов. При переводе термины из глоссария обеспечивают последовательные и точные переводы.", - "glossaries.aboutFormat": "Каждый термин имеет исходное слово и переводы на несколько языков. Выберите глоссарий на странице перевода, чтобы применить его.", - "glossaries.toast.created": "Глоссарий создан", - "glossaries.toast.createdDesc": "Глоссарий \"{name}\" создан.", - "glossaries.toast.imported": "Глоссарий импортирован", - "glossaries.toast.importedDesc": "Глоссарий \"{name}\" импортирован.", - "glossaries.toast.updated": "Глоссарий обновлён", - "glossaries.toast.updatedDesc": "Глоссарий \"{name}\" обновлён.", - "glossaries.toast.deleted": "Глоссарий удалён", - "glossaries.toast.deletedDesc": "Глоссарий удалён.", - "glossaries.toast.error": "Ошибка", - "glossaries.toast.errorCreate": "Не удалось создать глоссарий", - "glossaries.toast.errorImport": "Не удалось импортировать глоссарий", - "glossaries.toast.errorUpdate": "Не удалось обновить глоссарий", - "glossaries.toast.errorDelete": "Не удалось удалить глоссарий", - "glossaries.dialog.title": "Новый глоссарий", - "glossaries.dialog.description": "Создайте глоссарий для ваших переводов", - "glossaries.dialog.nameLabel": "Название", - "glossaries.dialog.namePlaceholder": "Мой глоссарий", - "glossaries.dialog.tabTemplates": "Шаблоны", - "glossaries.dialog.tabFile": "Файл", - "glossaries.dialog.tabManual": "Вручную", - "glossaries.dialog.cancel": "Отмена", - "glossaries.dialog.creating": "Создание…", - "glossaries.dialog.importing": "Импорт…", - "glossaries.dialog.importBtn": "Импортировать", - "glossaries.dialog.selectPrompt": "Выбрать", - "glossaries.dialog.createBtn": "Создать", - "glossaries.dialog.createEmpty": "Создать пустой", - "glossaries.dialog.terms": "терминов", - "glossaries.dialog.templatesDesc": "Выберите готовый шаблон", - "glossaries.dialog.templatesEmpty": "Нет доступных шаблонов", - "glossaries.dialog.dropTitle": "Перетащите CSV-файл сюда", - "glossaries.dialog.dropOr": "или", - "glossaries.dialog.dropFormats": "CSV, TSV, TXT", - "glossaries.termEditor.addTerm": "Добавить термин", - "glossaries.termEditor.maxReached": "Достигнуто максимум {max} терминов в глоссарии.", - "glossaries.dialog.formatTitle": "Формат", - "glossaries.dialog.formatDesc": "источник,цель (по одной на строку)", - "glossaries.dialog.formatNote": "Первая строка пропускается при обнаружении заголовка", - "glossaries.dialog.errorFormat": "Неподдерживаемый формат", - "glossaries.dialog.errorSize": "Файл слишком большой", - "glossaries.dialog.errorEmpty": "Пустой файл", - "glossaries.dialog.errorRead": "Ошибка чтения", - "glossaries.dialog.parsing": "Обработка…", - "glossaries.dialog.termsImported": "терминов импортировано", - "glossaries.dialog.changeFile": "Изменить файл", - "glossaries.dialog.retry": "Повторить", - "glossaries.edit.title": "Modifier le glossaire", - "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", - "glossaries.edit.nameLabel": "Nom du glossaire", - "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", - "glossaries.edit.sourceLang": "Langue source", - "glossaries.edit.targetLang": "Langue cible", - "glossaries.edit.termsLabel": "Termes ({count} valides)", - "glossaries.edit.exportCsv": "Exporter CSV", - "glossaries.edit.importCsv": "Importer CSV", - "glossaries.edit.cancel": "Annuler", - "glossaries.edit.saving": "Enregistrement...", - "glossaries.edit.saveChanges": "Enregistrer les modifications", - "glossaries.edit.importFailedTitle": "Échec de l'importation", - "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", - "glossaries.edit.importSuccessTitle": "Importation réussie", - "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", - "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", - "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", - "glossaries.delete.title": "Supprimer le glossaire", - "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", - "glossaries.delete.warning": "Cette action est irréversible", - "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", - "glossaries.delete.cancel": "Annuler", - "glossaries.delete.deleting": "Suppression...", - "glossaries.delete.deleteBtn": "Supprimer", - "glossaries.upgrade.title": "Glossaires", - "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", - "glossaries.upgrade.feature1": "Créez plusieurs glossaires", - "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", - "glossaries.upgrade.feature3": "Importez/exportez via CSV", - "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", - "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", - "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", - "glossaries.upgrade.proLabel": "Pro", - "glossaries.upgrade.upgradeBtn": "Passer à Pro", - "glossaries.loading": "Chargement...", - "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", - "glossaries.howItWorks.step1Title": "Configurez ici", - "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", - "glossaries.howItWorks.step2Title": "Activez dans Traduire", - "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", - "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", - "glossaries.howItWorks.goToTranslate": "Aller à Traduire", - "glossaries.status.unsaved": "Non enregistré", - "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", - "glossaries.status.inactive": "Inactif", - "glossaries.instructions.whatForBold": "À quoi ça sert ?", - "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", - "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", - "glossaries.instructions.charCount": "{count} caractères", - "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", - "glossaries.instructions.clearAll": "Tout effacer", - "glossaries.instructions.saving": "Enregistrement…", - "glossaries.instructions.saved": "Enregistré", - "glossaries.presets.whatForBold": "À quoi ça sert ?", - "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", - "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", - "glossaries.presets.creating": "Création…", - "glossaries.presets.alreadyImported": "Déjà importé", - "glossaries.presets.it.title": "IT / Logiciel", - "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", - "glossaries.presets.legal.title": "Juridique / Contrats", - "glossaries.presets.legal.desc": "Droit des affaires, contentieux", - "glossaries.presets.medical.title": "Médical / Santé", - "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", - "glossaries.presets.finance.title": "Finance / Comptabilité", - "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", - "glossaries.presets.marketing.title": "Marketing / Publicité", - "glossaries.presets.marketing.desc": "Digital, branding, analytics", - "glossaries.presets.hr.title": "RH / Ressources Humaines", - "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", - "glossaries.presets.scientific.title": "Scientifique / Recherche", - "glossaries.presets.scientific.desc": "Publications, thèses, articles", - "glossaries.presets.ecommerce.title": "E-commerce / Vente", - "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", - "glossaries.grid.title": "Vos", - "glossaries.grid.titleHighlight": "glossaires", - "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", - "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", - "glossaries.grid.activeTranslation": "Traduction active :", - "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", - "glossaries.badge.compatible": "Compatible", - "glossaries.badge.otherTarget": "Autre cible", - "glossaries.card.editTerms": "Modifier les termes", - "glossaries.card.created": "Создано", - "glossaries.card.term": "термин", - "glossaries.card.delete": "Supprimer", - "glossaries.grid.searchPlaceholder": "Search a glossary…", - "glossaries.grid.noResults": "No results for this search.", - "glossaries.detail.backToList": "Back to glossaries", - "glossaries.detail.save": "Save", - "glossaries.detail.savedTitle": "Saved", - "glossaries.detail.savedDesc": "The glossary has been updated.", - "glossaries.detail.settingsTitle": "Settings", - "glossaries.detail.sourceLang": "Source language", - "glossaries.detail.targetLang": "Target language", - "glossaries.detail.termsTitle": "Terms", - "glossaries.detail.terms": "terms", - "glossaries.detail.searchTerms": "Filter…", - "glossaries.detail.noTerms": "No terms yet.", - "glossaries.detail.addFirstTerm": "Add the first term", - "glossaries.detail.addTerm": "Add a term", - "glossaries.detail.maxReached": "Maximum limit reached", - "glossaries.detail.source": "Source", - "glossaries.detail.target": "Target", - "glossaries.detail.sourcePlaceholder": "source term", - "glossaries.detail.targetPlaceholder": "target term", - "glossaries.detail.csvTitle": "CSV", - "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", - "glossaries.detail.export": "Export", - "glossaries.detail.import": "Import", - "glossaries.detail.dangerTitle": "Danger zone", - "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", - "glossaries.detail.deleteGlossary": "Delete this glossary", - "glossaries.detail.confirmDelete": "Confirm deletion?", - "glossaries.detail.confirm": "Confirm", - "glossaries.detail.cancel": "Cancel", - "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", - "glossaries.detail.sourceLocked": "fixed", - "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", - "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", - "glossaries.detail.notFoundTitle": "Glossary not found", - "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", - "glossaries.detail.maxTermsTitle": "Limit reached", - "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", - "glossaries.detail.importEmptyTitle": "Empty file", - "glossaries.detail.importEmptyDesc": "No terms detected in this file.", - "glossaries.detail.importedTitle": "Imported", - "glossaries.detail.importedDesc": "{count} terms imported.", - "glossaries.detail.importErrorTitle": "Read error", - "glossaries.detail.importErrorDesc": "Unable to read the file.", - "apiKeys.webhook.title": "Intégration Webhook", - "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", - "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", - "apiKeys.webhook.codeParam": "webhook_url", - "translate.mode.label": "Mode de traduction", - "translate.mode.classic": "Classique", - "translate.mode.classicDesc": "Rapide", - "translate.mode.proLlm": "Pro LLM", - "translate.mode.proLlmDesc": "Contextuel", - "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", - "translate.mode.upgradeLink": "Passer à Pro", - "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", - "pricing.nav.back": "Назад", - "pricing.nav.home": "Главная", - "pricing.nav.mySubscription": "Моя подписка", - "pricing.header.badge": "ИИ-модели обновлены — март 2026", - "pricing.header.title": "Тариф для любых задач", - "pricing.header.subtitle": "Переводите документы Word, Excel и PowerPoint с сохранением исходного форматирования. Без API-ключей.", - "pricing.billing.monthly": "Ежемесячно", - "pricing.billing.yearly": "Ежегодно", - "pricing.plans.free.name": "Бесплатный", - "pricing.plans.starter.name": "Starter", - "pricing.plans.pro.name": "Pro", - "pricing.plans.business.name": "Business", - "pricing.plans.enterprise.name": "Enterprise", - "pricing.plans.free.description": "Отлично для знакомства с приложением", - "pricing.plans.starter.description": "Для частных лиц и небольших проектов", - "pricing.plans.pro.description": "Для профессионалов и растущих команд", - "pricing.plans.business.description": "Для команд и организаций", - "pricing.plans.enterprise.description": "Индивидуальные решения для крупных организаций", - "pricing.plans.pro.highlight": "Самый популярный", - "pricing.plans.pro.badge": "ПОПУЛЯРНЫЙ", - "pricing.plans.enterprise.badge": "ПО ЗАПРОСУ", - "pricing.plans.free.feat1": "5 документов / месяц", - "pricing.plans.free.feat2": "До 15 страниц на документ", - "pricing.plans.free.feat3": "Google Переводчик включён", - "pricing.plans.free.feat4": "Все языки (130+)", - "pricing.plans.free.feat5": "Поддержка сообщества", - "pricing.plans.starter.feat1": "50 документов / месяц", - "pricing.plans.starter.feat2": "До 50 страниц на документ", - "pricing.plans.starter.feat3": "Google Переводчик + DeepL", - "pricing.plans.starter.feat4": "Файлы до 10 МБ", - "pricing.plans.starter.feat5": "Поддержка по эл. почте", - "pricing.plans.starter.feat6": "История за 30 дней", - "pricing.plans.pro.feat1": "200 документов / месяц", - "pricing.plans.pro.feat2": "До 200 страниц на документ", - "pricing.plans.pro.feat3": "Базовый ИИ-перевод", - "pricing.plans.pro.feat4": "Google Переводчик + DeepL", - "pricing.plans.pro.feat5": "Файлы до 25 МБ", - "pricing.plans.pro.feat6": "Пользовательские глоссарии", - "pricing.plans.pro.feat7": "Приоритетная поддержка", - "pricing.plans.pro.feat8": "История за 90 дней", - "pricing.plans.business.feat1": "1 000 документов / месяц", - "pricing.plans.business.feat2": "До 500 страниц на документ", - "pricing.plans.business.feat3": "Базовый + Премиум ИИ (Claude Haiku)", - "pricing.plans.business.feat4": "Все провайдеры перевода", - "pricing.plans.business.feat5": "Файлы до 50 МБ", - "pricing.plans.business.feat6": "Доступ к API (10 000 вызовов/мес.)", - "pricing.plans.business.feat7": "Вебхуки уведомлений", - "pricing.plans.business.feat8": "Выделенная поддержка", - "pricing.plans.business.feat9": "История за 1 год", - "pricing.plans.business.feat10": "Расширенная аналитика", - "pricing.plans.enterprise.feat1": "Безлимитные документы", - "pricing.plans.enterprise.feat2": "Все ИИ-модели (GPT-5, Claude Opus 4.6…)", - "pricing.plans.enterprise.feat3": "Локальное развёртывание или выделенное облако", - "pricing.plans.enterprise.feat4": "SLA 99,9 % гарантировано", - "pricing.plans.enterprise.feat5": "Выделенная поддержка 24/7", - "pricing.plans.enterprise.feat6": "White-label", - "pricing.plans.enterprise.feat7": "Безлимитные команды", - "pricing.plans.enterprise.feat8": "Индивидуальные интеграции", - "pricing.card.onRequest": "По запросу", - "pricing.card.free": "Бесплатно", - "pricing.card.perMonth": "/мес.", - "pricing.card.billedYearly": "К оплате {price} € / год", - "pricing.card.documents": "Документы", - "pricing.card.pagesMax": "Макс. страниц", - "pricing.card.aiTranslation": "ИИ-перевод", - "pricing.card.unlimited": "Безлимит", - "pricing.card.perMonthStat": "/ месяц", - "pricing.card.perDoc": "стр. / док.", - "pricing.card.aiEssential": "Базовый", - "pricing.card.aiEssentialPremium": "Базовый + Премиум", - "pricing.card.aiCustom": "Индивидуальный", - "pricing.card.myPlan": "Мой тариф", - "pricing.card.managePlan": "Управлять тарифом", - "pricing.card.startFree": "Начать бесплатно", - "pricing.card.contactUs": "Связаться с нами", - "pricing.card.choosePlan": "Выбрать этот тариф", - "pricing.card.processing": "Обработка…", - "pricing.comparison.title": "Подробное сравнение", - "pricing.comparison.subtitle": "Всё, что входит в каждый тариф", - "pricing.comparison.feature": "Функция", - "pricing.comparison.docsPerMonth": "Документы / месяц", - "pricing.comparison.pagesMaxPerDoc": "Макс. страниц / документ", - "pricing.comparison.maxFileSize": "Макс. размер файла", - "pricing.comparison.googleTranslation": "Google Переводчик", - "pricing.comparison.deepl": "DeepL", - "pricing.comparison.aiEssential": "Базовый ИИ-перевод", - "pricing.comparison.aiPremium": "Премиум ИИ-перевод", - "pricing.comparison.apiAccess": "Доступ к API", - "pricing.comparison.priorityProcessing": "Приоритетная обработка", - "pricing.comparison.support": "Поддержка", - "pricing.comparison.support.community": "Сообщество", - "pricing.comparison.support.email": "Эл. почта", - "pricing.comparison.support.priority": "Приоритетная", - "pricing.comparison.support.dedicated": "Выделенная", - "pricing.comparison.mb": "МБ", - "pricing.credits.title": "Дополнительные кредиты", - "pricing.credits.subtitle": "Нужно больше? Купите кредиты поштучно, без подписки.", - "pricing.credits.perPage": "1 кредит = 1 переведённая страница.", - "pricing.credits.bestValue": "Лучшая ценность", - "pricing.credits.unit": "кредитов", - "pricing.credits.centsPerCredit": "коп. / кредит", - "pricing.credits.buy": "Купить", - "pricing.trust.encryption.title": "Сквозное шифрование", - "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 при хранении", - "pricing.trust.languages.title": "130+ языков", - "pricing.trust.languages.sub": "Включая арабский, персидский, иврит (RTL)", - "pricing.trust.parallel.title": "Параллельная обработка", - "pricing.trust.parallel.sub": "Сверхбыстрая многопоточная ИИ", - "pricing.trust.availability.title": "Доступно 24/7", - "pricing.trust.availability.sub": "99,9 % гарантированный аптайм", - "pricing.aiModels.title": "Наши ИИ-модели — март 2026", - "pricing.aiModels.essential.title": "Базовый ИИ-перевод", - "pricing.aiModels.essential.plan": "Тариф Pro", - "pricing.aiModels.essential.descPrefix": "На базе", - "pricing.aiModels.essential.descSuffix": "— самой экономичной ИИ-модели 2026 года. Качество на уровне frontier-моделей при стоимости в десятки раз ниже.", - "pricing.aiModels.essential.modelName": "наша базовая ИИ-модель", - "pricing.aiModels.essential.context": "163K токенов контекста", - "pricing.aiModels.essential.value": "Отличное соотношение цены и качества", - "pricing.aiModels.premium.title": "Премиум ИИ-перевод", - "pricing.aiModels.premium.plan": "Тариф Business", - "pricing.aiModels.premium.descPrefix": "На базе", - "pricing.aiModels.premium.descSuffix": "от Anthropic — высокая точность на юридических, медицинских и сложных технических документах.", - "pricing.aiModels.premium.context": "200K токенов контекста", - "pricing.aiModels.premium.precision": "Наивысшая точность", - "pricing.faq.title": "Часто задаваемые вопросы", - "pricing.faq.q1": "Могу ли я сменить тариф в любое время?", - "pricing.faq.a1": "Да. Повышение тарифа применяется сразу с пересчётом. Понижение вступает в силу в конце текущего периода.", - "pricing.faq.q2": "Что такое «Базовый ИИ-перевод»?", - "pricing.faq.a2": "Это наш ИИ-движок. Он понимает контекст ваших документов, сохраняет вёрстку и обрабатывает технические термины намного лучше классического перевода.", - "pricing.faq.q3": "В чём разница между базовым и премиум ИИ-переводом?", - "pricing.faq.a3": "Базовый ИИ использует оптимизированную модель (отличное соотношение цены и качества). Премиум ИИ использует Claude 3.5 Haiku от Anthropic, более точный на юридических, медицинских и сложных технических документах.", - "pricing.faq.q4": "Сохраняются ли мои документы после перевода?", - "pricing.faq.a4": "Переведённые файлы доступны в зависимости от тарифа (30 дней Starter, 90 дней Pro, 1 год Business). Они зашифрованы при хранении и передаче.", - "pricing.faq.q5": "Что произойдёт при превышении месячной квоты?", - "pricing.faq.a5": "Вы можете докупить кредиты поштучно или повысить тариф. Уведомление приходит при достижении 80 % использования.", - "pricing.faq.q6": "Есть ли бесплатный пробный период для платных тарифов?", - "pricing.faq.a6": "Бесплатный тариф постоянный и не требует банковской карты. Для тарифов Pro и Business свяжитесь с нами для получения 14-дневного пробного доступа.", - "pricing.faq.q7": "Какие форматы файлов поддерживаются?", - "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx), а скоро и PDF. Все тарифы поддерживают одинаковые форматы.", - "pricing.cta.title": "Готовы начать?", - "pricing.cta.subtitle": "Начните бесплатно, без банковской карты. Повысьте тариф, когда понадобится.", - "pricing.cta.createAccount": "Создать бесплатный аккаунт", - "pricing.cta.login": "Войти", - "pricing.toast.demo": "Деморежим — Stripe ещё не настроен. В рабочей среде вы были бы перенаправлены на страницу оплаты для активации тарифа {planId}.", - "pricing.toast.networkError": "Сетевая ошибка. Пожалуйста, попробуйте снова.", - "pricing.toast.paymentError": "Ошибка при создании платежа.", - "register.title": "Создать аккаунт", - "register.subtitle": "Начните переводить бесплатно", - "register.error.failed": "Ошибка регистрации", - "register.name.label": "Имя", - "register.name.placeholder": "Ваше имя", - "register.name.error": "Имя должно содержать не менее 2 символов", - "register.email.label": "Электронная почта", - "register.email.placeholder": "you@example.com", - "register.email.error": "Недействительный адрес эл. почты", - "register.password.label": "Пароль", - "register.password.error": "Пароль должен содержать не менее 8 символов, включая заглавную букву, строчную букву и цифру", - "register.password.show": "Показать пароль", - "register.password.hide": "Скрыть пароль", - "register.password.strengthLabel": "Надёжность:", - "register.password.strength.weak": "Слабая", - "register.password.strength.medium": "Средняя", - "register.password.strength.strong": "Сильная", - "register.confirmPassword.label": "Подтвердите пароль", - "register.confirmPassword.error": "Пароли не совпадают", - "register.confirmPassword.show": "Показать", - "register.confirmPassword.hide": "Скрыть", - "register.submit.creating": "Создание аккаунта...", - "register.submit.create": "Создать аккаунт", - "register.hasAccount": "Уже есть аккаунт?", - "register.login": "Войти", - "register.terms.prefix": "Создавая аккаунт, вы принимаете наши", - "register.terms.link": "условия использования", - - - "login.errorTitle": "Login Error", - "login.welcomeBack": "Welcome back", - "login.signInToContinue": "Sign in to continue translating", - "login.email": "Email", - "login.emailPlaceholder": "you@example.com", - "login.password": "Password", - "login.forgotPassword": "Forgot password?", - "login.passwordPlaceholder": "••••••••", - "login.signingIn": "Signing in...", - "login.signIn": "Sign In", - "login.noAccount": "Don't have an account?", - "login.signUpFree": "Sign up for free", - "login.orContinueWith": "или продолжить по электронной почте", - "login.google.connecting": "Подключение…", - "login.google.errorGeneric": "Произошла ошибка при входе через Google.", - "login.google.errorFailed": "Не удалось войти через Google. Повторите попытку.", - "forgotPassword.enterEmail": "Please enter your email address", - "forgotPassword.error": "An error occurred", - "forgotPassword.title": "Forgot Password", - "forgotPassword.checkEmail": "Check your inbox", - "forgotPassword.subtitle": "Enter your email to receive a reset link", - "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", - "forgotPassword.emailLabel": "Email address", - "forgotPassword.emailPlaceholder": "you@example.com", - "forgotPassword.sending": "Sending...", - "forgotPassword.sendLink": "Send reset link", - "forgotPassword.backToLogin": "Back to login", - "forgotPassword.loading": "Loading...", - "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", - "resetPassword.passwordMismatch": "Passwords do not match", - "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", - "resetPassword.error": "An error occurred", - "resetPassword.invalidLink": "Invalid link", - "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", - "resetPassword.requestNewLink": "Request new link", - "resetPassword.successTitle": "Password reset", - "resetPassword.newPasswordTitle": "New password", - "resetPassword.successSubtitle": "You will be redirected to login", - "resetPassword.subtitle": "Set your new password", - "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", - "resetPassword.newPassword": "New password", - "resetPassword.showPassword": "Show password", - "resetPassword.hidePassword": "Hide password", - "resetPassword.confirmPassword": "Confirm password", - "resetPassword.resetting": "Resetting...", - "resetPassword.resetPassword": "Reset password", - "resetPassword.backToLogin": "Back to login", - "resetPassword.loading": "Loading...", - "common.loading": "Загрузка...", - "profile.header.title": "Мой профиль", - "profile.header.subtitle": "Управление аккаунтом и настройками.", - "profile.tabs.account": "Аккаунт", - "profile.tabs.subscription": "Подписка", - "profile.tabs.preferences": "Настройки", - "profile.account.user": "Пользователь", - "profile.account.memberSince": "Участник с", - "profile.plan.label": "Тариф", - "profile.plan.free": "Free", - "profile.plan.starter": "Starter", - "profile.plan.pro": "Pro", - "profile.plan.business": "Business", - "profile.plan.enterprise": "Enterprise", - "profile.plan.pricePerMonth": "{price} €/мес.", - "profile.subscription.canceling": "Отменяется", - "profile.subscription.active": "Активна", - "profile.subscription.unknown": "Неизвестно", - "profile.subscription.accessUntil": "Доступ до", - "profile.subscription.renewalOn": "Продление", - "profile.subscription.upgradePlan": "Перейти на платный тариф", - "profile.subscription.changePlan": "Сменить тариф", - "profile.subscription.manageBilling": "Управление оплатой", - "profile.subscription.billingUnavailable": "Портал оплаты недоступен.", - "profile.subscription.billingError": "Ошибка доступа к порталу оплаты.", - "profile.subscription.cancelSuccess": "Подписка отменена. Доступ сохраняется до конца текущего периода.", - "profile.subscription.cancelError": "Ошибка при отмене.", - "profile.subscription.networkError": "Ошибка сети.", - "profile.usage.title": "Использование за этот месяц", - "profile.usage.resetOn": "Сброс", - "profile.usage.documents": "Документы", - "profile.usage.pages": "Страницы", - "profile.usage.extraCredits": "дополнительный кредит", - "profile.usage.extraCreditsPlural": "дополнительных кредитов", - "profile.usage.quotaReached": "Лимит достигнут", - "profile.usage.quotaReachedDesc": "Перейдите на более высокий тариф, чтобы продолжить.", - "profile.usage.unlockMore": "Разблокируйте больше переводов с платным тарифом.", - "profile.usage.viewPlans": "Посмотреть тарифы", - "profile.usage.includedInPlan": "Включено в ваш тариф", - "profile.danger.title": "Опасная зона", - "profile.danger.description": "Отмена вступает в силу в конце текущего периода. Доступ сохраняется до этой даты.", - "profile.danger.confirm": "Вы уверены? Это действие нельзя отменить.", - "profile.danger.confirmCancel": "Подтвердить отмену", - "profile.danger.cancelSubscription": "Отменить мою подписку", - "profile.danger.keep": "Нет, оставить", - "profile.prefs.interfaceLang": "Язык интерфейса", - "profile.prefs.interfaceLangDesc": "Язык определяется автоматически на основе настроек браузера. Вы можете изменить его вручную.", - "profile.prefs.defaultTargetLang": "Язык перевода по умолчанию", - "profile.prefs.selectLanguage": "Выберите язык", - "profile.prefs.defaultTargetLangDesc": "Этот язык будет автоматически выбираться для ваших переводов.", - "profile.prefs.save": "Сохранить", - "profile.prefs.theme": "Тема", - "profile.prefs.themeDesc": "Выберите внешний вид интерфейса", - "profile.prefs.cache": "Кэш", - "profile.prefs.cacheDesc": "Очистка локального кэша может решить некоторые проблемы отображения.", - "profile.prefs.clearing": "Очистка...", - "profile.prefs.clearCache": "Очистить кэш", - "settings.title": "Настройки", - "settings.subtitle": "Общая конфигурация приложения", - "settings.formats.title": "Поддерживаемые форматы", - "settings.formats.subtitle": "Типы документов, которые можно перевести", - "settings.formats.formulas": "Формулы", - "settings.formats.styles": "Стили", - "settings.formats.images": "Изображения", - "settings.formats.headers": "Колонтитулы", - "settings.formats.tables": "Таблицы", - "settings.formats.slides": "Слайды", - "settings.formats.notes": "Заметки", - "settings.cache.title": "Кэш", - "settings.cache.desc": "Очистка локального кэша может решить некоторые проблемы отображения.", - "settings.cache.clearing": "Очистка...", - "settings.cache.clear": "Очистить кэш", - "services.title": "Провайдеры перевода", - "services.subtitle": "Провайдеры настраиваются администратором. Вы можете увидеть, какие из них доступны для вашего аккаунта.", - "services.loading": "Загрузка провайдеров...", - "services.noProviders": "Провайдеры не настроены. Обратитесь к администратору.", - "services.classic": "Классический перевод", - "services.llmPro": "LLM · Контекстный (Pro)", - "services.available": "Доступен", - "services.model": "Модель", - "services.adminOnly.title": "Настройка провайдеров доступна только администратору", - "services.adminOnly.desc": "API-ключи, выбор моделей и активация провайдеров управляются исключительно администратором в панели управления. Вам не нужно вводить API-ключ.", - "apiKeys.title": "API-ключи", - "apiKeys.subtitle": "Управляйте API-ключами для программного доступа к API перевода.", - "apiKeys.loading": "Загрузка...", - "apiKeys.sectionTitle": "API и автоматизация", - "apiKeys.sectionDesc": "Генерируйте и управляйте API-ключами для автоматизации рабочих процессов", - "apiKeys.keysUsed": "{total} из {max} ключей использовано", - "apiKeys.maxReached": "Достигнуто максимальное количество ключей. Отзовите ключ, чтобы создать новый.", - "apiKeys.canGenerate": "Вы можете создать ещё {count} ключ", - "apiKeys.canGeneratePlural": "Вы можете создать ещё {count} ключей", - "apiKeys.generateNew": "Создать новый ключ", - "apiKeys.keyRevoked": "Ключ отозван", - "apiKeys.keyRevokedDesc": "API-ключ успешно отозван.", - "apiKeys.keyNotFound": "Ключ не найден", - "apiKeys.keyNotFoundDesc": "API-ключ больше не существует. Возможно, он уже был отозван.", - "apiKeys.error": "Ошибка", - "apiKeys.revokeError": "Не удалось отозвать API-ключ. Попробуйте снова.", - "apiKeys.limitReached": "Лимит достигнут", - "apiKeys.limitReachedDesc": "Вы достигли максимума в 10 API-ключей. Отзовите существующий ключ, чтобы создать новый.", - "apiKeys.proRequired": "Требуется тариф Pro", - "apiKeys.proRequiredDesc": "API-ключи — функция тарифа Pro. Пожалуйста, повысьте свой тариф.", - "apiKeys.generateError": "Не удалось сгенерировать API-ключ. Попробуйте снова.", - "apiKeys.upgrade.title": "API-ключи", - "apiKeys.upgrade.subtitle": "Автоматизируйте переводы с помощью доступа к API", - "apiKeys.upgrade.feat1": "Неограниченное количество API-ключей", - "apiKeys.upgrade.feat2": "Автоматизация перевода документов", - "apiKeys.upgrade.feat3": "Уведомления через вебхуки", - "apiKeys.upgrade.feat4": "Режимы перевода LLM", - "apiKeys.upgrade.proFeature": "API-ключи — функция тарифа {pro}. Повысьте тариф, чтобы разблокировать автоматизацию API.", - "apiKeys.upgrade.pro": "Pro", - "apiKeys.upgrade.cta": "Перейти на Pro", - "apiKeys.dialog.maxTitle": "Достигнуто максимальное количество ключей", - "apiKeys.dialog.maxDesc": "Вы достигли максимума в 10 API-ключей. Отзовите существующий ключ перед созданием нового.", - "apiKeys.dialog.close": "Закрыть", - "apiKeys.dialog.generated": "API-ключ создан!", - "apiKeys.dialog.generatedDesc": "Ваш новый API-ключ создан. Скопируйте его сейчас — он больше не будет показан.", - "apiKeys.dialog.important": "Важно:", - "apiKeys.dialog.importantDesc": "Это единственный раз, когда вы видите этот ключ. Храните его в безопасности.", - "apiKeys.dialog.apiKey": "API-ключ", - "apiKeys.dialog.name": "Имя:", - "apiKeys.dialog.done": "Готово", - "apiKeys.dialog.copied": "Я скопировал ключ", - "apiKeys.dialog.generateTitle": "Создать новый API-ключ", - "apiKeys.dialog.generateDesc": "Создайте новый API-ключ для программного доступа к API перевода.", - "apiKeys.dialog.keyName": "Имя ключа (необязательно)", - "apiKeys.dialog.keyNamePlaceholder": "напр. Продакшен, Стегинг", - "apiKeys.dialog.keyNameHint": "Описательное имя для идентификации ключа в будущем.", - "apiKeys.dialog.nameTooLong": "Имя должно содержать не более {max} символов", - "apiKeys.dialog.nameInvalid": "Имя может содержать только буквы, цифры, пробелы, дефисы и подчёркивания", - "apiKeys.dialog.cancel": "Отмена", - "apiKeys.dialog.generating": "Генерация...", - "apiKeys.dialog.generate": "Создать ключ", - "apiKeys.table.name": "Имя", - "apiKeys.table.prefix": "Префикс", - "apiKeys.table.created": "Создан", - "apiKeys.table.lastUsed": "Последнее использование", - "apiKeys.table.never": "Никогда", - "apiKeys.table.actions": "Действия", - "apiKeys.table.revoke": "Отозвать", - "apiKeys.table.copyPrefix": "Копировать префикс ключа", - "apiKeys.table.revokeKey": "Отозвать ключ", - "apiKeys.revokeDialog.title": "Отзыв API-ключа", - "apiKeys.revokeDialog.desc": "Вы уверены, что хотите отозвать ключ \"{name}\"? Это действие нельзя отменить.", - "apiKeys.revokeDialog.confirm": "Да, отозвать", - "apiKeys.revokeDialog.cancel": "Отмена", - "context.proTitle": "Функция Pro", - "context.proDesc": "Контекст и профессиональные глоссарии доступны на тарифах Pro, Business и Enterprise. Они обеспечивают более точные переводы благодаря инструкциям и словарю, специфичному для вашей области.", - "context.viewPlans": "Посмотреть тарифы", - "context.title": "Контекст и глоссарий", - "context.subtitle": "Улучшите качество перевода с помощью инструкций и словаря, специфичного для вашей области.", - "context.presets.title": "Профессиональные глоссарии", - "context.presets.desc": "Загрузите полный глоссарий с инструкциями и специализированной терминологией", - "context.instructions.title": "Инструкции контекста", - "context.instructions.desc": "Инструкции, которым ИИ будет следовать при переводе", - "context.instructions.placeholder": "Напр.: Вы переводите техническую документацию по HVAC. Используйте точную инженерную терминологию...", - "context.glossary.title": "Технический глоссарий", - "context.glossary.desc": "Формат: источник=цель (по одному на строку). Глоссарии, загруженные через пресет, можно редактировать.", - "context.glossary.terms": "терминов в глоссарии", - "context.clearAll": "Очистить всё", - "context.saving": "Сохранение...", - "context.save": "Сохранить", - "translate.glossary.title": "Глоссарий", - "translate.glossary.select": "Выбрать глоссарий", - "translate.glossary.none": "Нет", - "translate.glossary.terms": "терминов", - "translate.glossary.proOnly": "Обновитесь до Pro для использования глоссариев", - "translate.glossary.myGlossaries": "Мои глоссарии", - "translate.glossary.fromTemplate": "Создать из шаблона", - "translate.glossary.noGlossaryForPair": "Нет глоссария для", - "translate.glossary.noGlossaries": "Нет глоссариев", - "translate.glossary.loading": "Загрузка...", - "translate.glossary.classicMode": "Нейтральный движок без глоссария (только ИИ)", - "translate.glossary.selectPlaceholder": "Выбрать глоссарий...", - "translate.glossary.multilingual": "МУЛЬТИЯЗЫЧНЫЙ", - "translate.glossary.noGlossaryAvailable": "Нет доступных глоссариев", - "translate.glossary.filterByLang": "Фильтр по языку", - "translate.glossary.active": "Активно", - "translate.glossary.inactive": "Неактивно", - "translate.glossary.availableTemplates": "Доступные шаблоны", - "translate.glossary.importing": "Импорт...", - "translate.glossary.imported": "(Импортировано)", - "translate.glossary.noGlossaryForSource": "Нет глоссария или шаблона для исходного языка", - "translate.glossary.createGlossary": "Создать глоссарий", - "translate.glossary.showAll": "Показать все глоссарии", - "translate.glossary.activePreview": "Предпросмотр активных совпадений:", - "translate.glossary.total": "всего", - "translate.glossary.moreTerms": "других терминов", - "translate.glossary.noTerms": "Нет терминов в этом глоссарии.", - "translate.glossary.sourceTerm": "Исходный термин", - "translate.glossary.translation": "Перевод", - "translate.glossary.addTerm": "Добавить термин", - "translate.glossary.disabledMode": "Нейтральный движок без применённого глоссария", - "translate.glossary.addTermError": "Ошибка при добавлении термина", - "translate.glossary.networkError": "Сетевая ошибка", - "translate.glossary.importFailed": "Ошибка импорта ({status})", - "translate.glossary.helpText": "Глоссарий обеспечивает точный перевод терминов. Выберите глоссарий, исходный язык которого соответствует оригинальному языку вашего документа.", - "translate.glossary.sourceWarning": "Внимание: Этот глоссарий использует исходный язык", - "translate.glossary.sourceWarningBut": "но ваш документ настроен на", - "translate.glossary.targetWarning": "Несовместимость цели: Этот глоссарий предназначен для перевода на", - "translate.glossary.targetWarningBut": "но ваш документ нацелен на", - "translate.glossary.targetWarningEnd": "Термины могут быть нерелевантны.", - "context.presets.createGlossary": "Создать глоссарий", - "context.presets.created": "Глоссарий создан", - "context.presets.createdDesc": "Глоссарий \"{name}\" создан с {count} терминами.", - "context.presets.hint": "Нажмите на пресет, чтобы создать глоссарий с предметными терминами. Управляйте глоссариями в разделе Глоссарии.", - "context.glossary.manage": "Управлять глоссариями", - "context.saved": "Сохранено", - "context.savedDesc": "Ваши контекстные инструкции сохранены.", - "admin.login.title": "Администрирование", - "admin.login.required": "Требуется вход", - "admin.login.password": "Пароль администратора", - "admin.login.connecting": "Подключение...", - "admin.login.access": "Войти в панель администратора", - "admin.login.restricted": "Доступ ограничен администраторами", - "admin.layout.checking": "Проверка аутентификации...", - "admin.dashboard.title": "Панель администратора", - "admin.dashboard.subtitle": "Панель управления администратора", - "admin.dashboard.refresh": "Обновить", - "admin.dashboard.refreshTooltip": "Обновить данные панели", - "admin.dashboard.config": "Конфигурация системы", - "admin.dashboard.maxFileSize": "Макс. размер файла:", - "admin.dashboard.translationService": "Служба перевода:", - "admin.dashboard.formats": "Форматы:", - "admin.nav.dashboard": "Dashboard", - "admin.nav.users": "Пользователи", - "admin.nav.pricing": "Цены и Stripe", - "admin.nav.providers": "Провайдеры", - "admin.nav.system": "Система", - "admin.nav.logs": "Журналы", - "admin.users.title": "Управление пользователями", - "admin.users.subtitle": "Просмотр и управление учётными записями", - "admin.users.planUpdated": "План обновлён", - "admin.users.planChanged": "План успешно изменён на \"{plan}\".", - "admin.users.unknownError": "Неизвестная ошибка", - "admin.users.error": "Ошибка", - "admin.users.planUpdateError": "Не удалось обновить план: {message}", - "admin.users.noKeys": "Нет ключей", - "admin.users.noKeysDesc": "У этого пользователя нет активных ключей API.", - "admin.users.keysRevoked": "Ключи отозваны", - "admin.users.keysRevokedDesc": "{count} ключ(ей) API успешно отозвано.", - "admin.users.revokeError": "Не удалось отозвать ключи: {message}", - "admin.users.retry": "Повторить", - "admin.system.title": "Система", - "admin.system.subtitle": "Мониторинг состояния системы и управление ресурсами", - "admin.system.quotas": "Квоты переводов", - "admin.system.resetQuotas": "Сбросить месячные квоты", - "admin.system.resetting": "Сброс...", - "admin.system.reset": "Сбросить", - "admin.system.allOperational": "Все системы работают", - "admin.system.issuesDetected": "Обнаружены проблемы в системе", - "admin.system.waitingData": "Ожидание данных...", - "admin.system.purging": "Очистка...", - "admin.system.clean": "Очистить", - "admin.system.purge": "Очистить", - "memento.title": "Откройте Momento", - "memento.slogan": "Momento — это больше, чем приложение для заметок. Это интеллектуальная экосистема, которая связывает, анализирует и развивает ваши идеи в реальном времени с помощью 6 ИИ-агентов и продвинутого семантического поиска.", - "memento.ctaFree": "Начать бесплатно", - "memento.ctaMore": "Узнать больше", - "common.backToHome": "Вернуться на главную", - "dashboard.topbar.interfaceLabel": "Интерфейс перевода", - "dashboard.topbar.premiumAccess": "Премиум-доступ", - "landing.hero.contextEngine": "Обнаружен перевод: Технический термин обслуживания для систем HVAC...", - "landing.hero.liveAnalysis": "Анализ в реальном времени", - "landing.hero.termsDetected": "терминов обнаружено", - "landing.steps.process": "ПРОЦЕСС", - "landing.translate.newProject": "Новый проект", - "landing.translate.title": "Перевести документ", - "landing.translate.subtitle": "Импортируйте файл и выберите целевой язык", - "landing.translate.sourceDocument": "Исходный документ", - "landing.translate.configuration": "Настройки", - "landing.translate.sourceLang": "Исходный язык", - "landing.translate.targetLang": "Целевой язык", - "landing.translate.provider": "Провайдер", - "landing.translate.startTranslation": "Начать перевод", - "landing.translate.zeroRetention": "Нулевое хранение", - "landing.translate.filesDeleted": "Файлы удаляются после обработки", - "landing.translate.dropHere": "Перетащите сюда", - "landing.translate.supportedFormats": "Поддерживаются файлы DOCX, XLSX, PPTX или PDF", - "landing.translate.aiAnalysis": "Активный ИИ-анализ", - "landing.translate.processing": "Обработка", - "landing.translate.preservingLayout": "Ваше форматирование сохраняется", - "layout.nav.apiAccess": "Доступ к API", - "layout.footer.terms": "Условия", - "layout.footer.privacy": "Конфиденциальность", - "fileUploader.uploadDocument": "Загрузить документ", - "fileUploader.uploadDesc": "Перетащите или нажмите, чтобы выбрать файл (Excel, Word, PowerPoint)", - "fileUploader.dropHere": "Перетащите файл сюда…", - "fileUploader.dragAndDrop": "Перетащите документ сюда", - "fileUploader.orClickBrowse": "или нажмите, чтобы выбрать", - "fileUploader.preview": "Предпросмотр", - "fileUploader.translationOptions": "Параметры перевода", - "fileUploader.configureSettings": "Настройте параметры перевода", - "fileUploader.targetLanguage": "Целевой язык", - "fileUploader.selectLanguage": "Выберите язык", - "fileUploader.translationProvider": "Поставщик перевода", - "fileUploader.selectProvider": "Выберите поставщика", - "fileUploader.advancedOptions": "Расширенные параметры", - "fileUploader.translateImages": "Переводить изображения", - "fileUploader.translating": "Перевод…", - "fileUploader.translateDocument": "Перевести документ", - "fileUploader.processing": "Обработка…", - "fileUploader.translationError": "Ошибка перевода", - "fileUploader.translationComplete": "Перевод завершён!", - "fileUploader.translationCompleteDesc": "Ваш документ успешно переведён с сохранением форматирования.", - "fileUploader.download": "Скачать переведённый документ", - "fileUploader.webgpuUnsupported": "WebGPU не поддерживается в этом браузере. Используйте Chrome 113+ или Edge 113+.", - "fileUploader.webllmNotLoaded": "Модель WebLLM не загружена. Перейдите в Настройки > Службы перевода, чтобы загрузить модель.", - "fileUploader.extracting": "Извлечение текстов из документа…", - "fileUploader.noTranslatable": "В документе не найден переводимый текст", - "fileUploader.foundTexts": "Найдено {count} текстов для перевода", - "fileUploader.translatingItem": "Перевод {current}/{total}: «{preview}»", - "fileUploader.reconstructing": "Восстановление документа…", - "fileUploader.translatingLocally": "Локальный перевод с WebLLM…", - "checkout.activating": "Активация…", - "checkout.activatingDesc": "Обновляем вашу подписку, подождите.", - "checkout.paymentConfirmed": "Платёж подтверждён!", - "checkout.subscriptionActivated": "Подписка активирована!", - "checkout.planActivated": "Тариф {plan} активирован!", - "checkout.redirectingToProfile": "Перенаправление в профиль…", - "checkout.paymentReceived": "Платёж получен", - "checkout.redirecting": "Перенаправление…", - "checkout.syncError": "Ошибка синхронизации", - "checkout.networkError": "Ошибка сети. Платёж подтверждён — перезагрузите профиль.", - "dashboard.checkoutSyncError": "Ошибка синхронизации платежа.", - "dashboard.networkRefresh": "Ошибка сети. Обновите страницу.", - "dashboard.continueToTranslate": "Перейти к переводу", - "langSelector.search": "Поиск…", - "langSelector.noResults": "Нет результатов", - "langSelector.source": "Источник", - "langSelector.target": "Цель", - "langSelector.swap": "Поменять", - "translateComplete.highQuality": "Высокое качество", - "translateComplete.segments": "Сегменты", - "translateComplete.characters": "Символы", - "translateComplete.confidence": "Уверенность", - "providerTheme.deepseek.badge": "Базовый", - "providerTheme.deepseek.subBadge": "Технический и экономичный", - "providerTheme.deepseek.desc": "Ультраточная и экономичная трансляция, идеально для технических документов и кода.", - "providerTheme.openai.badge": "Премиум", - "providerTheme.openai.subBadge": "Высокая точность", - "providerTheme.openai.desc": "Мировой стандарт ИИ. Максимальная согласованность и строгое соблюдение стиля.", - "providerTheme.minimax.badge": "Продвинутый", - "providerTheme.minimax.subBadge": "Производительность", - "providerTheme.minimax.desc": "Невероятная скорость и превосходное понимание сложных структур.", - "providerTheme.openrouter.badge": "Экспресс", - "providerTheme.openrouter.subBadge": "Мульти-модель", - "providerTheme.openrouter.desc": "Единый доступ к лучшим open-source моделям, оптимизированным для перевода.", - "providerTheme.openrouter_premium.badge": "Ультра", - "providerTheme.openrouter_premium.subBadge": "Максимальный контекст", - "providerTheme.openrouter_premium.desc": "С помощью современных моделей (GPT-4o, Claude Sonnet 4.6) для длинных документов.", - "providerTheme.zai.badge": "Специализированный", - "providerTheme.zai.subBadge": "Финансы и право", - "providerTheme.zai.desc": "Модель точно настроена для требовательных бизнес-терминологий (юриспруденция, финансы).", - "providerTheme.default.badge": "Современный", - "providerTheme.default.subBadge": "ИИ-рассуждение", - "providerTheme.default.desc": "Перевод большой языковой моделью (LLM) с расширенным семантическим анализом.", - "providerTheme.classic.google.label": "Google Переводчик", - "providerTheme.classic.google.desc": "Сверхбыстрый перевод более 130 языков. Рекомендуется для общих потоков.", - "providerTheme.classic.deepl.label": "DeepL Pro", - "providerTheme.classic.deepl.desc": "Высокоточная трансляция, известная своей беглостью и естественностью формулировок.", - "providerTheme.classic.google_cloud.label": "Google Cloud API", - "providerTheme.classic.google_cloud.desc": "Профессиональный облачный движок, оптимизированный для обработки больших объёмов документов.", - "providerSelector.noClassic": "Стандартный переводчик недоступен.", - "providerSelector.noLlm": "Модель ИИ не настроена.", - "providerSelector.costOne": "Стоимость: 1 кредит за страницу", - "providerSelector.costFive": "Стоимость: 5 кредитов за страницу (Премиум-фактор)", - "providerSelector.unlockContextual": "Разблокируйте премиум-контекстный перевод для ваших документов.", - "translate.header.processing": "Идёт обработка", - "translate.header.aiActive": "ИИ-анализ активен", - "translate.header.aiActiveDesc": "Ваша компоновка сохраняется нашим контекстным движком.", - "translate.header.completed": "Завершено", - "translate.header.completedTitle": "Перевод завершён", - "translate.header.proSpace": "Pro-пространство", - "translate.header.translateDoc": "Перевести документ", - "translate.header.translateDocDesc": "Сохраните оригинальную компоновку с нашим движком перевода сверхвысокой точности.", - "translate.upload.nativeFormat": "Родной формат", - "translate.fileType.word": "Word (.docx)", - "translate.fileType.excel": "Excel (.xlsx)", - "translate.fileType.slides": "Слайды (.pptx)", - "translate.fileType.pdf": "PDF (.pdf)", - "translate.startTranslation": "Начать перевод", - "translate.submit": "Отправка…", - "translate.chooseTargetLang": "Пожалуйста, выберите целевой язык", - "translate.pleaseLoadFile": "Пожалуйста, сначала загрузите файл", - "translate.contextEngineActive": "Контекстный движок активен", - "translate.phase1": "Фаза 1: Инициализация", - "translate.phase2": "Фаза 2: Контекстная реконструкция", - "translate.stat.segments": "сегментов", - "translate.stat.precision": "точность", - "translate.stat.speedLabel": "скорость", - "translate.stat.turbo": "Турбо", - "translate.stat.time": "время", - "translate.complete.masterQuality": "✓ Мастер-качество", - "translate.download": "Скачать", - "translate.newTranslation": "+ Новый перевод", - "translate.failedTitle": "Ошибка перевода", - "translate.retry": "Повторить", - "translate.uploadAnother": "Загрузить другой файл", - "translate.monitor": "ИИ-монитор", - "translate.summary": "Сводка", - "translate.cancelProcess": "⟳ Отменить процесс", - "translate.layoutIntegrity": "Целостность макета", - "translate.secureHundred": "100% БЕЗОПАСНО", - "translate.okHundred": "100% OK", - "translate.preserveLayout": "Сохранить макет", - "translate.preserveLayoutDesc": "Сохранить макет", - "translate.textOnly": "Только текст", - "translate.textOnlyDesc": "Быстрый перевод только текста", - "translate.unavailableStandard": "Недоступно в стандартном режиме (только ИИ)", - "apiKeys.noKeysGenerated": "Ключи не созданы", - "apiKeys.copied": "Скопировано!", - "services.fallback.google.label": "Google Переводчик", - "services.fallback.google.desc": "Быстрый перевод, 130+ языков", - "settings.formats.excel.name": "Excel", - "settings.formats.word.name": "Word", - "settings.formats.powerpoint.name": "PowerPoint", - "pricing.dashboard": "Панель", - "pricing.okSymbol": "✓", - "pricing.errSymbol": "✕", - }, - // ═══════════════════════════════════════════════════════════════ - // JAPANESE (ja) - // ═══════════════════════════════════════════════════════════════ - ja: { - "auth.brandName": "Wordly", - "dashboard.nav.translate": "翻訳する", - "dashboard.nav.profile": "マイプロフィール", - "dashboard.nav.settings": "設定", - "dashboard.nav.context": "コンテキスト", - "dashboard.nav.services": "サービス", - "dashboard.nav.apiKeys": "APIキー", - "dashboard.nav.glossaries": "用語集", - "dashboard.header.title": "ダッシュボード", - "dashboard.header.subtitle": "翻訳を管理", - "dashboard.header.toggleMenu": "メニュー", - "dashboard.header.profileTitle": "マイプロフィール", - "dashboard.sidebar.theme": "テーマ", - "dashboard.sidebar.signOut": "ログアウト", - "dashboard.sidebar.backHome": "ホームに戻る", - "dashboard.sidebar.upgradeToPro": "Proにアップグレード →", - "cookieConsent.title": "WordlyのCookie", - "cookieConsent.description": "アプリの動作に必要なCookieを使用します(セッション、セキュリティ、言語)。許可をいただいた場合、トラフィックの測定と製品の改善のためのオプションCookieも使用します。", - "cookieConsent.acceptAll": "すべて許可", - "cookieConsent.essentialOnly": "必要なもののみ", - "cookieConsent.learnMore": "詳細", - "landing.nav.why": "選ばれる理由", - "landing.nav.formats": "対応形式", - "landing.nav.pricing": "料金プラン", - "landing.nav.login": "ログイン", - "landing.nav.startFree": "無料で始める", - "landing.hero.tag": "プロフェッショナル文書AI", - "landing.hero.titleLine1": "ドキュメントを翻訳。", - "landing.hero.titleLine2": "フォーマットは完璧に保持。", - "landing.hero.description": "SmartArt、グラフ、目次、図形、複雑なレイアウトを元のまま保持する唯一の翻訳ツール。", - "landing.hero.ctaMain": "無料で始める — 月2ファイル", - "landing.hero.ctaSec": "プランを見る", - "landing.hero.deleted": "ファイルは60分後に削除", - "landing.hero.noHidden": "隠し料金なし", - "landing.hero.preview": "支払い前にプレビュー", - "landing.hero.formattedOk": "フォーマットOK", - "landing.hero.aiActive": "AI翻訳アクティブ", - "landing.steps.title": "使い方", - "landing.steps.subtitle": "3つのステップ。フォーマット損失ゼロ。", - "landing.steps.step1.num": "01", - "landing.steps.step1.title": "ファイルをアップロード", - "landing.steps.step1.desc": "Excel、Word、PowerPoint、PDFファイルをドラッグ&ドロップ。", - "landing.steps.step2.num": "02", - "landing.steps.step2.title": "言語とエンジンを選択", - "landing.steps.step2.desc": "翻訳先の言語とエンジンを選択 — クラシックまたはコンテキスト対応AI。", - "landing.steps.step3.num": "03", - "landing.steps.step3.title": "結果をダウンロード", - "landing.steps.step3.desc": "元の文書と同じフォーマットの翻訳文書を取得。", - "landing.features.tag": "AI翻訳エンジン", - "landing.features.title": "あなたの専門性を理解する翻訳", - "landing.features.description": "AIモデルがコンテキストを分析し、専門用語を尊重し、画像内のテキストまで翻訳します。", - "landing.features.context.title": "業界コンテキスト", - "landing.features.context.desc": "業界を説明すれば、汎用的でない、最適化された翻訳を取得できます。", - "landing.features.glossary.title": "業界用語集", - "landing.features.glossary.desc": "専門用語を定義。CTAは「Call To Action」ではなく「空調処理ユニット」のまま。", - "landing.features.vision.title": "画像認識", - "landing.features.vision.desc": "画像、図、グラフに埋め込まれたテキストを検出して翻訳。", - "landing.features.demo.source": "原文(FR)", - "landing.features.demo.google": "Google翻訳", - "landing.features.demo.ours": "当社のAI", - "landing.layout.title": "あなたのフォーマット、", - "landing.layout.title2": "完璧に保持", - "landing.layout.subtitle": "他の翻訳ツールはレイアウトを崩します。私たちは違います。", - "landing.layout.p1.title": "SmartArtと図", - "landing.layout.p1.desc": "組織図、フローチャート、階層図 — すべて同一に翻訳。", - "landing.layout.p2.title": "目次", - "landing.layout.p2.desc": "目次のエントリ、ページ番号、相互参照を正しく更新。", - "landing.layout.p3.title": "グラフとチャート", - "landing.layout.p3.desc": "タイトル、軸ラベル、凡例、系列名 — すべて翻訳。", - "landing.layout.p4.title": "図形とテキストボックス", - "landing.layout.p4.desc": "四角形、角丸ブロック、吹き出し — すべてローカライズ。", - "landing.layout.p5.title": "ヘッダーとフッター", - "landing.layout.p5.desc": "ヘッダー、フッター、脚注を確実に翻訳。", - "landing.layout.p6.title": "130以上の言語", - "landing.layout.p6.desc": "Google翻訳、DeepL、プロフェッショナルグレードのAIエンジン。", - "landing.formats.title": "すべての形式、", - "landing.formats.title2": "すべての要素", - "landing.formats.subtitle": "他社が見落とす部分も翻訳。ビジネスに完璧なドキュメントを。", - "landing.formats.word.name": "Word", - "landing.formats.word.i1": "段落と見出し", - "landing.formats.word.i2": "表とグラフ", - "landing.formats.word.i3": "SmartArt図", - "landing.formats.word.i4": "目次", - "landing.formats.word.i5": "ヘッダーとフッター", - "landing.formats.word.i6": "図形とテキストボックス", - "landing.formats.word.i7": "脚注と文末脚注", - "landing.formats.excel.name": "Excel", - "landing.formats.excel.i1": "セルの値", - "landing.formats.excel.i2": "シート名", - "landing.formats.excel.i3": "グラフとラベル", - "landing.formats.excel.i4": "ヘッダーとフッター", - "landing.formats.excel.i5": "結合セルを保持", - "landing.formats.pptx.name": "PowerPoint", - "landing.formats.pptx.i1": "スライドテキストとノート", - "landing.formats.pptx.i2": "グラフと図", - "landing.formats.pptx.i3": "図形とテキストボックス", - "landing.formats.pptx.i4": "マスターレイアウト", - "landing.formats.pptx.i5": "アニメーションを保持", - "landing.formats.pdf.name": "PDF", - "landing.formats.pdf.i1": "テキストベースPDF", - "landing.formats.pdf.i2": "レイアウトを保持", - "landing.formats.pdf.i3": "画像を元の位置に保持", - "landing.formats.pdf.i4": "表を維持", - "landing.formats.pdf.i5": "DOCXまたはPDFで出力", - "landing.pricing.title": "シンプルで透明な料金", - "landing.pricing.subtitle": "見たままの価格。隠し料金なし。", - "landing.pricing.monthly": "月額", - "landing.pricing.annual": "年額", - "landing.pricing.bestValue": "一番人気", - "landing.pricing.month": "/月", - "landing.pricing.footer": "表示価格がお支払いいただく金額です。翻訳後の追加料金は一切ありません。", - "landing.pricing.starter.name": "Starter", - "landing.pricing.starter.desc": "個人や小規模プロジェクト向け", - "landing.pricing.starter.f1": "月50ドキュメント", - "landing.pricing.starter.f2": "1ドキュメント最大50ページ", - "landing.pricing.starter.f3": "Google翻訳 + DeepL", - "landing.pricing.starter.f4": "最大10 MBのファイル", - "landing.pricing.starter.cta": "始める", - "landing.pricing.pro.name": "Pro", - "landing.pricing.pro.desc": "プロフェッショナル向け", - "landing.pricing.pro.f1": "月200ドキュメント", - "landing.pricing.pro.f2": "1ドキュメント最大200ページ", - "landing.pricing.pro.f3": "AI翻訳", - "landing.pricing.pro.f4": "Google + DeepL込み", - "landing.pricing.pro.f5": "カスタム用語集とプロンプト", - "landing.pricing.pro.f6": "優先サポート", - "landing.pricing.pro.cta": "Proを試す", - "landing.pricing.business.name": "ビジネス", - "landing.pricing.business.desc": "大量処理が必要なチーム向け", - "landing.pricing.business.f1": "月1,000ドキュメント", - "landing.pricing.business.f2": "1ドキュメント最大500ページ", - "landing.pricing.business.f3": "プレミアムAI(Claude)", - "landing.pricing.business.f4": "全プロバイダー + API", - "landing.pricing.business.f5": "Webhookと自動化", - "landing.pricing.business.f6": "チームシート5席", - "landing.pricing.business.cta": "お問い合わせ", - "landing.cta.title": "30秒で翻訳を開始", - "landing.cta.subtitle": "クレジットカード不要。今すぐ無料でお試しください。", - "landing.cta.button": "無料アカウント作成", - "landing.cta.secure": "AES-256暗号化で保護", - "landing.footer.desc": "インテリジェントな文書翻訳のエキスパート。レイアウトの芸術とコンテキストAIの科学を融合。", - "landing.footer.product": "製品", - "landing.footer.resources": "リソース", - "landing.footer.legal": "法務", - "landing.footer.rights": "© 2026 Wordly.art — All rights reserved.", - "dashboard.translate.pageTitle": "ドキュメントを翻訳", - "dashboard.translate.pageSubtitle": "ファイルをインポートして翻訳先言語を選択", - "dashboard.translate.errorNotificationTitle": "エラー", - "dashboard.translate.dropzone.uploadAria": "ファイルドロップゾーン", - "dashboard.translate.dropzone.title": "ファイルをここにドラッグ&ドロップ", - "dashboard.translate.dropzone.subtitle": "またはクリックして選択(DOCX、XLSX、PPTX、PDF)", - "dashboard.translate.dropzone.replaceFile": "ファイルを置き換え", - "dashboard.translate.language.source": "翻訳元言語", - "dashboard.translate.language.target": "翻訳先言語", - "dashboard.translate.language.loading": "言語を読み込み中…", - "dashboard.translate.language.autoDetect": "自動検出", - "dashboard.translate.language.selectPlaceholder": "選択…", - "dashboard.translate.language.loadErrorPrefix": "言語の読み込みに失敗しました", - "dashboard.translate.provider.loading": "プロバイダーを読み込み中…", - "dashboard.translate.provider.noneConfigured": "プロバイダーが設定されていません", - "dashboard.translate.provider.modelTitle": "モデル", - "dashboard.translate.provider.sectionTitle": "プロバイダー", - "dashboard.translate.provider.llmDivider": "AI・コンテキスト認識", - "dashboard.translate.provider.llmDividerPro": "AI・コンテキスト認識(Pro)", - "dashboard.translate.provider.upgrade": "Proにアップグレード", - "dashboard.translate.provider.upgradeSuffix": "AI翻訳をアンロック", - "dashboard.translate.trust.zeroRetention": "データ保持なし", - "dashboard.translate.trust.deletedAfter": "処理後にファイルを削除", - "dashboard.translate.actions.uploading": "アップロード中…", - "dashboard.translate.actions.translate": "翻訳する", - "dashboard.translate.actions.filePrefix": "ファイル:", - "dashboard.translate.actions.cancel": "キャンセル", - "dashboard.translate.actions.tryAgain": "再試行", - "dashboard.translate.steps.uploading": "ファイルをアップロード中…", - "dashboard.translate.steps.starting": "翻訳を開始中…", - "dashboard.translate.complete.title": "翻訳完了!", - "dashboard.translate.complete.descNamed": "ファイル{name}の翻訳が正常に完了しました。", - "dashboard.translate.complete.descGeneric": "ファイルの翻訳が正常に完了しました。", - "dashboard.translate.complete.downloading": "ダウンロード中…", - "dashboard.translate.complete.download": "ダウンロード", - "dashboard.translate.complete.newTranslation": "新しい翻訳", - "dashboard.translate.complete.toastOkTitle": "成功", - "dashboard.translate.complete.toastOkDesc": "{name} のダウンロードが完了しました。", - "dashboard.translate.complete.toastFailTitle": "失敗", - "dashboard.translate.complete.toastFailDesc": "翻訳に失敗しました。もう一度お試しください。", - "dashboard.translate.sourceDocument": "ソースドキュメント", - "dashboard.translate.configuration": "設定", - "dashboard.translate.translating": "翻訳中", - "dashboard.translate.liveMonitor": "ライブモニター", - "dashboard.translate.summary": "概要", - "dashboard.translate.engine": "エンジン", - "dashboard.translate.confidence": "信頼度", - "dashboard.translate.cancel": "キャンセル", - "dashboard.translate.segments": "セグメント", - "dashboard.translate.characters": "文字", - "dashboard.translate.elapsed": "経過時間", - "dashboard.translate.segPerMin": "セグ/分", - "dashboard.translate.highQuality": "高品質", - "dashboard.translate.quality": "品質", - "dashboard.translate.completed": "翻訳完了", - "dashboard.translate.replace": "置換", - "dashboard.translate.pdfMode.title": "PDF翻訳モード", - "dashboard.translate.pdfMode.preserveLayout": "レイアウト保持", - "dashboard.translate.pdfMode.textOnly": "テキストのみ", - "dashboard.translate.pdfMode.preserveLayoutDesc": "画像、表、書式を保持。シンプルなPDFに最適。", - "dashboard.translate.pdfMode.textOnlyDesc": "すべてのテキストを完璧に翻訳。レイアウト問題のないクリーンな出力。", - "dashboard.translate.pipeline.upload": "アップロード", - "dashboard.translate.pipeline.analyze": "分析", - "dashboard.translate.pipeline.translate": "翻訳", - "dashboard.translate.pipeline.rebuild": "再構築", - "dashboard.translate.pipeline.finalize": "完了", - "dashboard.translate.progress.processingFallback": "処理中…", - "dashboard.translate.progress.connectionLost": "接続が失われました。再試行中…", - "dashboard.translate.progress.failedTitle": "翻訳失敗", - "dashboard.translate.error.unexpected": "予期しないエラーが発生しました。もう一度お試しください。", - "dashboard.translate.error.noResult": "翻訳結果が得られませんでした。ドキュメントにテキストが含まれていることを確認し、再試行するか別のエンジンを選択してください。", - "dashboard.translate.error.apiKey": "APIキーが無効または不足しています。管理者に連絡してAPIキーを設定してください。", - "dashboard.translate.error.quota": "利用制限に達しました。数分後にもう一度お試しいただくか、別のエンジンを選択してください。", - "dashboard.translate.error.timeout": "翻訳サービスへの接続がタイムアウトしました。ネットワークを確認して再試行してください。", - "dashboard.translate.error.sessionExpired": "セッションが期限切れです。再試行をクリックして翻訳を再開してください。", - "dashboard.translate.error.empty": "ドキュメントが空か、翻訳可能なテキストが含まれていません(スキャンPDF画像?)。", - "dashboard.translate.error.unsupported": "サポートされていないファイル形式または破損したファイルです。", - "dashboard.translate.error.connection": "接続が切断されました。ネットワークを確認して再試行してください。", - "dashboard.translate.error.generic": "翻訳失敗:{detail}", - "dashboard.translate.error.title": "翻訳失敗", - "dashboard.translate.retry": "再翻訳", - "dashboard.translate.newFile": "新しいファイル", - "dashboard.translate.modeAI": "AIモード", - "dashboard.translate.modeClassic": "クラシックモード", - "dashboard.translate.glossaryLLMHint": "AIモードで用語集が利用可能", - "dashboard.translate.submitting": "送信中...", - "dashboard.translate.submit": "翻訳を開始", - "dashboard.translate.noFile": "先にファイルをアップロードしてください", - "dashboard.translate.noTargetLang": "翻訳先の言語を選択してください", - "glossaries.yourGlossaries": "あなたの用語集", - "glossaries.title": "用語集とコンテキスト", - "glossaries.description": "用語集とコンテキスト指示を管理して、より正確な翻訳を実現します。", - "glossaries.createNew": "新規作成", - "glossaries.empty": "用語集はまだありません", - "glossaries.emptyDesc": "最初の用語集を作成するか、上のプロフェッショナルプリセットを読み込んでください", - "glossaries.defineTerms": "用語", - "glossaries.aboutTitle": "用語集について", - "glossaries.aboutDesc": "用語集を使用すると、特定の用語の正確な翻訳を定義できます。翻訳時に用語集の用語が使用され、一貫した正確な翻訳が保証されます。", - "glossaries.aboutFormat": "各用語にはソース語と複数言語の翻訳があります。翻訳ページで用語集を選択して適用してください。", - "glossaries.toast.created": "用語集を作成しました", - "glossaries.toast.createdDesc": "用語集「{name}」を作成しました。", - "glossaries.toast.imported": "用語集をインポートしました", - "glossaries.toast.importedDesc": "用語集「{name}」をインポートしました。", - "glossaries.toast.updated": "用語集を更新しました", - "glossaries.toast.updatedDesc": "用語集「{name}」を更新しました。", - "glossaries.toast.deleted": "用語集を削除しました", - "glossaries.toast.deletedDesc": "用語集を削除しました。", - "glossaries.toast.error": "エラー", - "glossaries.toast.errorCreate": "用語集の作成に失敗しました", - "glossaries.toast.errorImport": "用語集のインポートに失敗しました", - "glossaries.toast.errorUpdate": "用語集の更新に失敗しました", - "glossaries.toast.errorDelete": "用語集の削除に失敗しました", - "glossaries.dialog.title": "新しい用語集", - "glossaries.dialog.description": "翻訳用の用語集を作成", - "glossaries.dialog.nameLabel": "名前", - "glossaries.dialog.namePlaceholder": "マイ用語集", - "glossaries.dialog.tabTemplates": "テンプレート", - "glossaries.dialog.tabFile": "ファイル", - "glossaries.dialog.tabManual": "手動", - "glossaries.dialog.cancel": "キャンセル", - "glossaries.dialog.creating": "作成中…", - "glossaries.dialog.importing": "インポート中…", - "glossaries.dialog.importBtn": "インポート", - "glossaries.dialog.selectPrompt": "選択", - "glossaries.dialog.createBtn": "作成", - "glossaries.dialog.createEmpty": "空で作成", - "glossaries.dialog.terms": "件", - "glossaries.dialog.templatesDesc": "定義済みテンプレートを選択", - "glossaries.dialog.templatesEmpty": "利用可能なテンプレートがありません", - "glossaries.dialog.dropTitle": "CSVファイルをここにドラッグ", - "glossaries.dialog.dropOr": "または", - "glossaries.dialog.dropFormats": "CSV、TSV、TXT", - "glossaries.termEditor.addTerm": "用語を追加", - "glossaries.termEditor.maxReached": "用語集ごとに最大 {max} 語に達しました。", - "glossaries.dialog.formatTitle": "形式", - "glossaries.dialog.formatDesc": "原文,訳文(1行につき1組)", - "glossaries.dialog.formatNote": "ヘッダーが検出された場合、最初の行はスキップされます", - "glossaries.dialog.errorFormat": "サポートされていない形式", - "glossaries.dialog.errorSize": "ファイルが大きすぎます", - "glossaries.dialog.errorEmpty": "空のファイル", - "glossaries.dialog.errorRead": "読み取りエラー", - "glossaries.dialog.parsing": "解析中…", - "glossaries.dialog.termsImported": "件インポート済み", - "glossaries.dialog.changeFile": "ファイルを変更", - "glossaries.dialog.retry": "再試行", - "glossaries.edit.title": "Modifier le glossaire", - "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", - "glossaries.edit.nameLabel": "Nom du glossaire", - "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", - "glossaries.edit.sourceLang": "Langue source", - "glossaries.edit.targetLang": "Langue cible", - "glossaries.edit.termsLabel": "Termes ({count} valides)", - "glossaries.edit.exportCsv": "Exporter CSV", - "glossaries.edit.importCsv": "Importer CSV", - "glossaries.edit.cancel": "Annuler", - "glossaries.edit.saving": "Enregistrement...", - "glossaries.edit.saveChanges": "Enregistrer les modifications", - "glossaries.edit.importFailedTitle": "Échec de l'importation", - "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", - "glossaries.edit.importSuccessTitle": "Importation réussie", - "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", - "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", - "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", - "glossaries.delete.title": "Supprimer le glossaire", - "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", - "glossaries.delete.warning": "Cette action est irréversible", - "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", - "glossaries.delete.cancel": "Annuler", - "glossaries.delete.deleting": "Suppression...", - "glossaries.delete.deleteBtn": "Supprimer", - "glossaries.upgrade.title": "Glossaires", - "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", - "glossaries.upgrade.feature1": "Créez plusieurs glossaires", - "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", - "glossaries.upgrade.feature3": "Importez/exportez via CSV", - "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", - "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", - "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", - "glossaries.upgrade.proLabel": "Pro", - "glossaries.upgrade.upgradeBtn": "Passer à Pro", - "glossaries.loading": "Chargement...", - "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", - "glossaries.howItWorks.step1Title": "Configurez ici", - "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", - "glossaries.howItWorks.step2Title": "Activez dans Traduire", - "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", - "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", - "glossaries.howItWorks.goToTranslate": "Aller à Traduire", - "glossaries.status.unsaved": "Non enregistré", - "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", - "glossaries.status.inactive": "Inactif", - "glossaries.instructions.whatForBold": "À quoi ça sert ?", - "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", - "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", - "glossaries.instructions.charCount": "{count} caractères", - "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", - "glossaries.instructions.clearAll": "Tout effacer", - "glossaries.instructions.saving": "Enregistrement…", - "glossaries.instructions.saved": "Enregistré", - "glossaries.presets.whatForBold": "À quoi ça sert ?", - "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", - "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", - "glossaries.presets.creating": "Création…", - "glossaries.presets.alreadyImported": "Déjà importé", - "glossaries.presets.it.title": "IT / Logiciel", - "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", - "glossaries.presets.legal.title": "Juridique / Contrats", - "glossaries.presets.legal.desc": "Droit des affaires, contentieux", - "glossaries.presets.medical.title": "Médical / Santé", - "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", - "glossaries.presets.finance.title": "Finance / Comptabilité", - "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", - "glossaries.presets.marketing.title": "Marketing / Publicité", - "glossaries.presets.marketing.desc": "Digital, branding, analytics", - "glossaries.presets.hr.title": "RH / Ressources Humaines", - "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", - "glossaries.presets.scientific.title": "Scientifique / Recherche", - "glossaries.presets.scientific.desc": "Publications, thèses, articles", - "glossaries.presets.ecommerce.title": "E-commerce / Vente", - "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", - "glossaries.grid.title": "Vos", - "glossaries.grid.titleHighlight": "glossaires", - "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", - "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", - "glossaries.grid.activeTranslation": "Traduction active :", - "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", - "glossaries.badge.compatible": "Compatible", - "glossaries.badge.otherTarget": "Autre cible", - "glossaries.card.editTerms": "Modifier les termes", - "glossaries.card.created": "作成日", - "glossaries.card.term": "用語", - "glossaries.card.delete": "Supprimer", - "glossaries.grid.searchPlaceholder": "Search a glossary…", - "glossaries.grid.noResults": "No results for this search.", - "glossaries.detail.backToList": "Back to glossaries", - "glossaries.detail.save": "Save", - "glossaries.detail.savedTitle": "Saved", - "glossaries.detail.savedDesc": "The glossary has been updated.", - "glossaries.detail.settingsTitle": "Settings", - "glossaries.detail.sourceLang": "Source language", - "glossaries.detail.targetLang": "Target language", - "glossaries.detail.termsTitle": "Terms", - "glossaries.detail.terms": "terms", - "glossaries.detail.searchTerms": "Filter…", - "glossaries.detail.noTerms": "No terms yet.", - "glossaries.detail.addFirstTerm": "Add the first term", - "glossaries.detail.addTerm": "Add a term", - "glossaries.detail.maxReached": "Maximum limit reached", - "glossaries.detail.source": "Source", - "glossaries.detail.target": "Target", - "glossaries.detail.sourcePlaceholder": "source term", - "glossaries.detail.targetPlaceholder": "target term", - "glossaries.detail.csvTitle": "CSV", - "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", - "glossaries.detail.export": "Export", - "glossaries.detail.import": "Import", - "glossaries.detail.dangerTitle": "Danger zone", - "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", - "glossaries.detail.deleteGlossary": "Delete this glossary", - "glossaries.detail.confirmDelete": "Confirm deletion?", - "glossaries.detail.confirm": "Confirm", - "glossaries.detail.cancel": "Cancel", - "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", - "glossaries.detail.sourceLocked": "fixed", - "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", - "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", - "glossaries.detail.notFoundTitle": "Glossary not found", - "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", - "glossaries.detail.maxTermsTitle": "Limit reached", - "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", - "glossaries.detail.importEmptyTitle": "Empty file", - "glossaries.detail.importEmptyDesc": "No terms detected in this file.", - "glossaries.detail.importedTitle": "Imported", - "glossaries.detail.importedDesc": "{count} terms imported.", - "glossaries.detail.importErrorTitle": "Read error", - "glossaries.detail.importErrorDesc": "Unable to read the file.", - "apiKeys.webhook.title": "Intégration Webhook", - "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", - "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", - "apiKeys.webhook.codeParam": "webhook_url", - "translate.mode.label": "Mode de traduction", - "translate.mode.classic": "Classique", - "translate.mode.classicDesc": "Rapide", - "translate.mode.proLlm": "Pro LLM", - "translate.mode.proLlmDesc": "Contextuel", - "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", - "translate.mode.upgradeLink": "Passer à Pro", - "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", - "pricing.nav.back": "戻る", - "pricing.nav.home": "ホーム", - "pricing.nav.mySubscription": "マイサブスクリプション", - "pricing.header.badge": "AIモデル更新 — 2026年3月", - "pricing.header.title": "あらゆるニーズに応えるプラン", - "pricing.header.subtitle": "Word、Excel、PowerPointドキュメントを元のレイアウトを保持したまま翻訳。APIキー不要。", - "pricing.billing.monthly": "月額", - "pricing.billing.yearly": "年額", - "pricing.plans.free.name": "無料", - "pricing.plans.starter.name": "Starter", - "pricing.plans.pro.name": "Pro", - "pricing.plans.business.name": "Business", - "pricing.plans.enterprise.name": "Enterprise", - "pricing.plans.free.description": "アプリを試すのに最適", - "pricing.plans.starter.description": "個人や小規模プロジェクト向け", - "pricing.plans.pro.description": "プロフェッショナルや成長中のチーム向け", - "pricing.plans.business.description": "チームや組織向け", - "pricing.plans.enterprise.description": "大規模組織向けカスタムソリューション", - "pricing.plans.pro.highlight": "一番人気", - "pricing.plans.pro.badge": "人気No.1", - "pricing.plans.enterprise.badge": "要相談", - "pricing.plans.free.feat1": "月5ドキュメント", - "pricing.plans.free.feat2": "1ドキュメントあたり最大15ページ", - "pricing.plans.free.feat3": "Google翻訳付き", - "pricing.plans.free.feat4": "全言語対応(130+)", - "pricing.plans.free.feat5": "コミュニティサポート", - "pricing.plans.starter.feat1": "月50ドキュメント", - "pricing.plans.starter.feat2": "1ドキュメントあたり最大50ページ", - "pricing.plans.starter.feat3": "Google翻訳 + DeepL", - "pricing.plans.starter.feat4": "最大10 MBのファイル", - "pricing.plans.starter.feat5": "メールサポート", - "pricing.plans.starter.feat6": "30日間の履歴", - "pricing.plans.pro.feat1": "月200ドキュメント", - "pricing.plans.pro.feat2": "1ドキュメントあたり最大200ページ", - "pricing.plans.pro.feat3": "Essential AI翻訳", - "pricing.plans.pro.feat4": "Google翻訳 + DeepL", - "pricing.plans.pro.feat5": "最大25 MBのファイル", - "pricing.plans.pro.feat6": "カスタム用語集", - "pricing.plans.pro.feat7": "優先サポート", - "pricing.plans.pro.feat8": "90日間の履歴", - "pricing.plans.business.feat1": "月1,000ドキュメント", - "pricing.plans.business.feat2": "1ドキュメントあたり最大500ページ", - "pricing.plans.business.feat3": "エッセンシャル + プレミアムAI(Claude Haiku)", - "pricing.plans.business.feat4": "全翻訳プロバイダー", - "pricing.plans.business.feat5": "最大50 MBのファイル", - "pricing.plans.business.feat6": "APIアクセス(月10,000コール)", - "pricing.plans.business.feat7": "通知Webhook", - "pricing.plans.business.feat8": "専任サポート", - "pricing.plans.business.feat9": "1年間の履歴", - "pricing.plans.business.feat10": "高度な分析", - "pricing.plans.enterprise.feat1": "無制限ドキュメント", - "pricing.plans.enterprise.feat2": "全AIモデル(GPT-5、Claude Opus 4.6…)", - "pricing.plans.enterprise.feat3": "オンプレミスまたは専用クラウド展開", - "pricing.plans.enterprise.feat4": "99.9% SLA保証", - "pricing.plans.enterprise.feat5": "24/7専任サポート", - "pricing.plans.enterprise.feat6": "ホワイトラベル", - "pricing.plans.enterprise.feat7": "無制限チーム", - "pricing.plans.enterprise.feat8": "カスタム連携", - "pricing.card.onRequest": "要相談", - "pricing.card.free": "無料", - "pricing.card.perMonth": "/月", - "pricing.card.billedYearly": "年額 {price} € 請求", - "pricing.card.documents": "ドキュメント", - "pricing.card.pagesMax": "最大ページ数", - "pricing.card.aiTranslation": "AI翻訳", - "pricing.card.unlimited": "無制限", - "pricing.card.perMonthStat": "/ 月", - "pricing.card.perDoc": "p / doc", - "pricing.card.aiEssential": "エッセンシャル", - "pricing.card.aiEssentialPremium": "エッセンシャル + プレミアム", - "pricing.card.aiCustom": "カスタム", - "pricing.card.myPlan": "現在のプラン", - "pricing.card.managePlan": "プランを管理", - "pricing.card.startFree": "無料で始める", - "pricing.card.contactUs": "お問い合わせ", - "pricing.card.choosePlan": "このプランを選択", - "pricing.card.processing": "処理中…", - "pricing.comparison.title": "詳細な比較", - "pricing.comparison.subtitle": "各プランに含まれるすべての機能", - "pricing.comparison.feature": "機能", - "pricing.comparison.docsPerMonth": "ドキュメント / 月", - "pricing.comparison.pagesMaxPerDoc": "最大ページ数 / ドキュメント", - "pricing.comparison.maxFileSize": "最大ファイルサイズ", - "pricing.comparison.googleTranslation": "Google翻訳", - "pricing.comparison.deepl": "DeepL", - "pricing.comparison.aiEssential": "エッセンシャルAI翻訳", - "pricing.comparison.aiPremium": "プレミアムAI翻訳", - "pricing.comparison.apiAccess": "APIアクセス", - "pricing.comparison.priorityProcessing": "優先処理", - "pricing.comparison.support": "サポート", - "pricing.comparison.support.community": "コミュニティ", - "pricing.comparison.support.email": "メール", - "pricing.comparison.support.priority": "優先", - "pricing.comparison.support.dedicated": "専任", - "pricing.comparison.mb": "MB", - "pricing.credits.title": "追加クレジット", - "pricing.credits.subtitle": "もっと必要ですか?サブスクリプションなしでクレジットを個別購入。", - "pricing.credits.perPage": "1クレジット = 1翻訳ページ。", - "pricing.credits.bestValue": "最もお得", - "pricing.credits.unit": "クレジット", - "pricing.credits.centsPerCredit": "セント / クレジット", - "pricing.credits.buy": "購入", - "pricing.trust.encryption.title": "エンドツーエンド暗号化", - "pricing.trust.encryption.sub": "TLS 1.3 + AES-256(保存時)", - "pricing.trust.languages.title": "130+言語", - "pricing.trust.languages.sub": "アラビア語、ペルシャ語、ヘブライ語(RTL)を含む", - "pricing.trust.parallel.title": "並列処理", - "pricing.trust.parallel.sub": "超高速マルチスレッドAI", - "pricing.trust.availability.title": "24/7利用可能", - "pricing.trust.availability.sub": "99.9%稼働率保証", - "pricing.aiModels.title": "AIモデル一覧 — 2026年3月", - "pricing.aiModels.essential.title": "エッセンシャルAI翻訳", - "pricing.aiModels.essential.plan": "Proプラン", - "pricing.aiModels.essential.descPrefix": "ベース:", - "pricing.aiModels.essential.descSuffix": "— 2026年で最も費用対効果の高いAIモデル。フロンティアモデルと同等の品質をわずかなコストで実現。", - "pricing.aiModels.essential.modelName": "Essential AIモデル", - "pricing.aiModels.essential.context": "163Kトークンのコンテキスト", - "pricing.aiModels.essential.value": "優れた費用対効果", - "pricing.aiModels.premium.title": "プレミアムAI翻訳", - "pricing.aiModels.premium.plan": "Businessプラン", - "pricing.aiModels.premium.descPrefix": "ベース:", - "pricing.aiModels.premium.descSuffix": "(Anthropic社製)— 法務、医療、複雑な技術文書に高精度。", - "pricing.aiModels.premium.context": "200Kトークンのコンテキスト", - "pricing.aiModels.premium.precision": "最高精度", - "pricing.faq.title": "よくある質問", - "pricing.faq.q1": "いつでもプランを変更できますか?", - "pricing.faq.a1": "はい。アップグレードは即時反映され、日割り計算されます。ダウングレードは現在の期間の終了時に適用されます。", - "pricing.faq.q2": "「エッセンシャルAI翻訳」とは何ですか?", - "pricing.faq.a2": "独自のAIエンジンです。ドキュメントの文脈を理解し、レイアウトを保持し、技術用語を従来の翻訳よりはるかに適切に処理します。", - "pricing.faq.q3": "エッセンシャルAIとプレミアムAIの違いは何ですか?", - "pricing.faq.a3": "Essential AIは最適化されたモデルを使用しています(コストパフォーマンスに優れています)。Premium AIはAnthropicのClaude 3.5 Haikuを使用し、法的、医学的、複雑な技術文書により正確です。", - "pricing.faq.q4": "翻訳後もドキュメントは保存されますか?", - "pricing.faq.a4": "翻訳済みファイルはプランに応じて利用可能です(Starter 30日、Pro 90日、Business 1年)。保存時および通信時は暗号化されています。", - "pricing.faq.q5": "月間枠を超えた場合はどうなりますか?", - "pricing.faq.a5": "追加クレジットを個別購入するか、プランをアップグレードできます。使用量が80%に達すると通知されます。", - "pricing.faq.q6": "有料プランの無料試用はありますか?", - "pricing.faq.a6": "無料プランは永続的でクレジットカード不要です。ProおよびBusinessプランについては、14日間のトライアルをご希望の場合はお問い合わせください。", - "pricing.faq.q7": "対応ファイル形式を教えてください。", - "pricing.faq.a7": "Word(.docx)、Excel(.xlsx/.xls)、PowerPoint(.pptx)、および近日PDF対応予定。すべてのプランで同じ形式に対応しています。", - "pricing.cta.title": "始める準備はできましたか?", - "pricing.cta.subtitle": "クレジットカード不要で無料開始。必要に応じてアップグレード。", - "pricing.cta.createAccount": "無料アカウント作成", - "pricing.cta.login": "ログイン", - "pricing.toast.demo": "デモモード — Stripeはまだ設定されていません。本番環境では、{planId}プランを有効化するための支払いページにリダイレクトされます。", - "pricing.toast.networkError": "ネットワークエラー。もう一度お試しください。", - "pricing.toast.paymentError": "支払いの作成中にエラーが発生しました。", - "register.title": "アカウント作成", - "register.subtitle": "無料で翻訳を始めましょう", - "register.error.failed": "登録に失敗しました", - "register.name.label": "名前", - "register.name.placeholder": "お名前", - "register.name.error": "名前は2文字以上で入力してください", - "register.email.label": "メールアドレス", - "register.email.placeholder": "you@example.com", - "register.email.error": "無効なメールアドレス", - "register.password.label": "パスワード", - "register.password.error": "パスワードは8文字以上で、大文字・小文字・数字をそれぞれ1つ以上含めてください", - "register.password.show": "パスワードを表示", - "register.password.hide": "パスワードを非表示", - "register.password.strengthLabel": "強度:", - "register.password.strength.weak": "弱い", - "register.password.strength.medium": "普通", - "register.password.strength.strong": "強い", - "register.confirmPassword.label": "パスワード確認", - "register.confirmPassword.error": "パスワードが一致しません", - "register.confirmPassword.show": "表示", - "register.confirmPassword.hide": "非表示", - "register.submit.creating": "アカウント作成中...", - "register.submit.create": "アカウントを作成", - "register.hasAccount": "すでにアカウントをお持ちですか?", - "register.login": "ログイン", - "register.terms.prefix": "アカウントを作成することで、当社の", - "register.terms.link": "利用規約に同意したことになります", - "login.signInToContinue": "Sign in to continue translating", - "login.email": "Email", - "login.emailPlaceholder": "you@example.com", - "login.password": "Password", - "login.forgotPassword": "Forgot password?", - "login.passwordPlaceholder": "••••••••", - "login.signingIn": "Signing in...", - "login.signIn": "Sign In", - "login.noAccount": "Don't have an account?", - "login.signUpFree": "Sign up for free", - "login.orContinueWith": "またはメールで続行", - "login.google.connecting": "接続中…", - "login.google.errorGeneric": "Google ログインでエラーが発生しました。", - "login.google.errorFailed": "Google ログインに失敗しました。もう一度お試しください。", - "forgotPassword.enterEmail": "Please enter your email address", - "forgotPassword.error": "An error occurred", - "forgotPassword.title": "Forgot Password", - "forgotPassword.checkEmail": "Check your inbox", - "forgotPassword.subtitle": "Enter your email to receive a reset link", - "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", - "forgotPassword.emailLabel": "Email address", - "forgotPassword.emailPlaceholder": "you@example.com", - "forgotPassword.sending": "Sending...", - "forgotPassword.sendLink": "Send reset link", - "forgotPassword.backToLogin": "Back to login", - "forgotPassword.loading": "Loading...", - "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", - "resetPassword.passwordMismatch": "Passwords do not match", - "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", - "resetPassword.error": "An error occurred", - "resetPassword.invalidLink": "Invalid link", - "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", - "resetPassword.requestNewLink": "Request new link", - "resetPassword.successTitle": "Password reset", - "resetPassword.newPasswordTitle": "New password", - "resetPassword.successSubtitle": "You will be redirected to login", - "resetPassword.subtitle": "Set your new password", - "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", - "resetPassword.newPassword": "New password", - "resetPassword.showPassword": "Show password", - "resetPassword.hidePassword": "Hide password", - "resetPassword.confirmPassword": "Confirm password", - "resetPassword.resetting": "Resetting...", - "resetPassword.resetPassword": "Reset password", - "resetPassword.backToLogin": "Back to login", - "resetPassword.loading": "Loading...", - - "common.loading": "読み込み中...", - "profile.header.title": "マイプロフィール", - "profile.header.subtitle": "アカウントと設定を管理します。", - "profile.tabs.account": "アカウント", - "profile.tabs.subscription": "サブスクリプション", - "profile.tabs.preferences": "設定", - "profile.account.user": "ユーザー", - "profile.account.memberSince": "登録日", - "profile.plan.label": "プラン", - "profile.plan.free": "Free", - "profile.plan.starter": "Starter", - "profile.plan.pro": "Pro", - "profile.plan.business": "Business", - "profile.plan.enterprise": "Enterprise", - "profile.plan.pricePerMonth": "{price} €/月", - "profile.subscription.canceling": "キャンセル中", - "profile.subscription.active": "有効", - "profile.subscription.unknown": "不明", - "profile.subscription.accessUntil": "アクセス可能期限", - "profile.subscription.renewalOn": "次回更新日", - "profile.subscription.upgradePlan": "有料プランにアップグレード", - "profile.subscription.changePlan": "プランを変更", - "profile.subscription.manageBilling": "支払い管理", - "profile.subscription.billingUnavailable": "支払いポータルは利用できません。", - "profile.subscription.billingError": "支払いポータルへのアクセス中にエラーが発生しました。", - "profile.subscription.cancelSuccess": "サブスクリプションがキャンセルされました。期間終了までアクセスできます。", - "profile.subscription.cancelError": "キャンセル中にエラーが発生しました。", - "profile.subscription.networkError": "ネットワークエラー。", - "profile.usage.title": "今月の使用量", - "profile.usage.resetOn": "リセット日", - "profile.usage.documents": "ドキュメント", - "profile.usage.pages": "ページ", - "profile.usage.extraCredits": "追加クレジット", - "profile.usage.extraCreditsPlural": "追加クレジット", - "profile.usage.quotaReached": "上限に達しました", - "profile.usage.quotaReachedDesc": "引き続きご利用いただくには、上位プランにアップグレードしてください。", - "profile.usage.unlockMore": "有料プランで翻訳数を増やせます。", - "profile.usage.viewPlans": "プランを見る", - "profile.usage.includedInPlan": "プランに含まれています", - "profile.danger.title": "危険区域", - "profile.danger.description": "キャンセルは現在の期間の終了時に反映されます。その日までアクセスは維持されます。", - "profile.danger.confirm": "本当によろしいですか?この操作は取り消せません。", - "profile.danger.confirmCancel": "キャンセルを確認", - "profile.danger.cancelSubscription": "サブスクリプションをキャンセルする", - "profile.danger.keep": "いいえ、維持します", - "profile.prefs.interfaceLang": "インターフェース言語", - "profile.prefs.interfaceLangDesc": "言語はブラウザに基づいて自動検出されます。手動で変更することもできます。", - "profile.prefs.defaultTargetLang": "デフォルトの翻訳先言語", - "profile.prefs.selectLanguage": "言語を選択", - "profile.prefs.defaultTargetLangDesc": "この言語が翻訳時に自動選択されます。", - "profile.prefs.save": "保存", - "profile.prefs.theme": "テーマ", - "profile.prefs.themeDesc": "インターフェースの外観を選択してください", - "profile.prefs.cache": "キャッシュ", - "profile.prefs.cacheDesc": "ローカルキャッシュをクリアすると、一部の表示問題が解決する場合があります。", - "profile.prefs.clearing": "クリア中...", - "profile.prefs.clearCache": "キャッシュをクリア", - "settings.title": "設定", - "settings.subtitle": "アプリケーションの全般設定", - "settings.formats.title": "対応フォーマット", - "settings.formats.subtitle": "翻訳可能なドキュメントの種類", - "settings.formats.formulas": "数式", - "settings.formats.styles": "スタイル", - "settings.formats.images": "画像", - "settings.formats.headers": "ヘッダー", - "settings.formats.tables": "テーブル", - "settings.formats.slides": "スライド", - "settings.formats.notes": "ノート", - "settings.cache.title": "キャッシュ", - "settings.cache.desc": "ローカルキャッシュをクリアすると、一部の表示問題が解決する場合があります。", - "settings.cache.clearing": "クリア中...", - "settings.cache.clear": "キャッシュをクリア", - "services.title": "翻訳プロバイダー", - "services.subtitle": "プロバイダーは管理者によって設定されます。現在アカウントで利用可能なプロバイダーを確認できます。", - "services.loading": "プロバイダーを読み込み中...", - "services.noProviders": "現在設定されているプロバイダーはありません。管理者にお問い合わせください。", - "services.classic": "クラシック翻訳", - "services.llmPro": "LLM · コンテキスト認識 (Pro)", - "services.available": "利用可能", - "services.model": "モデル", - "services.adminOnly.title": "プロバイダーの設定は管理者のみ", - "services.adminOnly.desc": "APIキー、モデルの選択、プロバイダーの有効化は管理者が管理パネルで管理します。APIキーを入力する必要はありません。", - "apiKeys.title": "APIキー", - "apiKeys.subtitle": "翻訳APIへのプログラムアクセス用APIキーを管理します。", - "apiKeys.loading": "読み込み中...", - "apiKeys.sectionTitle": "API & 自動化", - "apiKeys.sectionDesc": "自動化ワークフロー用のAPIキーを生成・管理します", - "apiKeys.keysUsed": "{max} 個中 {total} 個使用", - "apiKeys.maxReached": "キーの上限に達しました。新しいキーを生成するには既存のキーを取り消してください。", - "apiKeys.canGenerate": "あと {count} 個のキーを生成できます", - "apiKeys.canGeneratePlural": "あと {count} 個のキーを生成できます", - "apiKeys.generateNew": "新しいキーを生成", - "apiKeys.keyRevoked": "キーが取り消されました", - "apiKeys.keyRevokedDesc": "APIキーは正常に取り消されました。", - "apiKeys.keyNotFound": "キーが見つかりません", - "apiKeys.keyNotFoundDesc": "APIキーは存在しません。既に取り消されている可能性があります。", - "apiKeys.error": "エラー", - "apiKeys.revokeError": "APIキーの取り消しに失敗しました。もう一度お試しください。", - "apiKeys.limitReached": "上限に達しました", - "apiKeys.limitReachedDesc": "APIキーは最大10個までです。新しいキーを生成するには既存のキーを取り消してください。", - "apiKeys.proRequired": "Pro機能が必要です", - "apiKeys.proRequiredDesc": "APIキーはPro機能です。アカウントをアップグレードしてください。", - "apiKeys.generateError": "APIキーの生成に失敗しました。もう一度お試しください。", - "apiKeys.upgrade.title": "APIキー", - "apiKeys.upgrade.subtitle": "APIアクセスで翻訳を自動化", - "apiKeys.upgrade.feat1": "無制限のAPIキーを生成", - "apiKeys.upgrade.feat2": "ドキュメント翻訳を自動化", - "apiKeys.upgrade.feat3": "Webhook通知", - "apiKeys.upgrade.feat4": "LLM翻訳モード", - "apiKeys.upgrade.proFeature": "APIキーは{pro}機能です。アップグレードしてAPI自動化を有効にしてください。", - "apiKeys.upgrade.pro": "Pro", - "apiKeys.upgrade.cta": "Proにアップグレード", - "apiKeys.dialog.maxTitle": "キーの上限に達しました", - "apiKeys.dialog.maxDesc": "APIキーは最大10個までです。新しいキーを生成する前に既存のキーを取り消してください。", - "apiKeys.dialog.close": "閉じる", - "apiKeys.dialog.generated": "APIキーが生成されました!", - "apiKeys.dialog.generatedDesc": "新しいAPIキーが作成されました。今すぐコピーしてください - 再度表示されることはありません。", - "apiKeys.dialog.important": "重要:", - "apiKeys.dialog.importantDesc": "このキーが表示されるのは今回のみです。安全に保管してください。", - "apiKeys.dialog.apiKey": "APIキー", - "apiKeys.dialog.name": "名前:", - "apiKeys.dialog.done": "完了", - "apiKeys.dialog.copied": "キーをコピーしました", - "apiKeys.dialog.generateTitle": "新しいAPIキーを生成", - "apiKeys.dialog.generateDesc": "翻訳APIへのプログラムアクセス用の新しいAPIキーを作成します。", - "apiKeys.dialog.keyName": "キー名(オプション)", - "apiKeys.dialog.keyNamePlaceholder": "例:本番環境、ステージング", - "apiKeys.dialog.keyNameHint": "後でこのキーを識別するためのわかりやすい名前。", - "apiKeys.dialog.nameTooLong": "名前は{max}文字以内で入力してください", - "apiKeys.dialog.nameInvalid": "名前に使用できるのは文字、数字、スペース、ハイフン、アンダースコアのみです", - "apiKeys.dialog.cancel": "キャンセル", - "apiKeys.dialog.generating": "生成中...", - "apiKeys.dialog.generate": "キーを生成", - "apiKeys.table.name": "名前", - "apiKeys.table.prefix": "プレフィックス", - "apiKeys.table.created": "作成日", - "apiKeys.table.lastUsed": "最終使用日", - "apiKeys.table.never": "未使用", - "apiKeys.table.actions": "操作", - "apiKeys.table.revoke": "取り消し", - "apiKeys.table.copyPrefix": "キーのプレフィックスをコピー", - "apiKeys.table.revokeKey": "キーを取り消し", - "apiKeys.revokeDialog.title": "APIキーを取り消し", - "apiKeys.revokeDialog.desc": "キー「{name}」を取り消してもよろしいですか?この操作は取り消せません。", - "apiKeys.revokeDialog.confirm": "はい、取り消します", - "apiKeys.revokeDialog.cancel": "キャンセル", - "context.proTitle": "Pro機能", - "context.proDesc": "コンテキストとプロフェッショナル用語集はPro、Business、Enterpriseプランでご利用いただけます。ドメイン固有の指示と語彙により、より正確な翻訳が提供されます。", - "context.viewPlans": "プランを見る", - "context.title": "コンテキスト & 用語集", - "context.subtitle": "ドメイン固有の指示と語彙で翻訳品質を向上させます。", - "context.presets.title": "プロフェッショナル用語集", - "context.presets.desc": "指示と専門用語を含む完全な用語集を読み込みます", - "context.instructions.title": "コンテキスト指示", - "context.instructions.desc": "翻訳中にAIが従う指示", - "context.instructions.placeholder": "例:HVAC技術文書を翻訳します。正確な工学用語を使用してください...", - "context.glossary.title": "技術用語集", - "context.glossary.desc": "形式:source=target(1行に1つ)。プリセットで読み込んだ用語集は編集可能です。", - "context.glossary.terms": "用語集の用語数", - "context.clearAll": "すべてクリア", - "context.saving": "保存中...", - "context.save": "保存", - "translate.glossary.title": "用語集", - "translate.glossary.select": "用語集を選択", - "translate.glossary.none": "なし", - "translate.glossary.terms": "件", - "translate.glossary.proOnly": "Proにアップグレードして用語集を使用", - "translate.glossary.myGlossaries": "マイ用語集", - "translate.glossary.fromTemplate": "テンプレートから作成", - "translate.glossary.noGlossaryForPair": "用語集なし", - "translate.glossary.noGlossaries": "用語集なし", - "translate.glossary.loading": "読み込み中...", - "translate.glossary.classicMode": "用語集なしのニュートラルエンジン(AIのみ)", - "translate.glossary.selectPlaceholder": "用語集を選択...", - "translate.glossary.multilingual": "多言語", - "translate.glossary.noGlossaryAvailable": "利用可能な用語集なし", - "translate.glossary.filterByLang": "言語で絞り込み", - "translate.glossary.active": "有効", - "translate.glossary.inactive": "無効", - "translate.glossary.availableTemplates": "利用可能なテンプレート", - "translate.glossary.importing": "インポート中...", - "translate.glossary.imported": "(インポート済み)", - "translate.glossary.noGlossaryForSource": "ソース言語の用語集・テンプレートなし", - "translate.glossary.createGlossary": "用語集を作成", - "translate.glossary.showAll": "すべての用語集を表示", - "translate.glossary.activePreview": "アクティブな一致のプレビュー:", - "translate.glossary.total": "合計", - "translate.glossary.moreTerms": "その他の用語", - "translate.glossary.noTerms": "この用語集には用語がありません。", - "translate.glossary.sourceTerm": "ソース用語", - "translate.glossary.translation": "翻訳", - "translate.glossary.addTerm": "用語を追加", - "translate.glossary.disabledMode": "用語集が適用されていないニュートラルエンジン", - "translate.glossary.addTermError": "用語の追加エラー", - "translate.glossary.networkError": "ネットワークエラー", - "translate.glossary.importFailed": "インポートに失敗しました ({status})", - "translate.glossary.helpText": "用語集は正確な用語翻訳を強制します。ソース言語がドキュメントの元の言語と一致する用語集を選択してください。", - "translate.glossary.sourceWarning": "警告:この用語集はソース言語を使用しています", - "translate.glossary.sourceWarningBut": "ただし、ドキュメントは次の言語に設定されています", - "translate.glossary.targetWarning": "ターゲットの不一致:この用語集は次の言語への翻訳用です", - "translate.glossary.targetWarningBut": "ただし、ドキュメントのターゲットは", - "translate.glossary.targetWarningEnd": "用語が関連しない場合があります。", - "context.presets.createGlossary": "用語集を作成", - "context.presets.created": "用語集を作成しました", - "context.presets.createdDesc": "用語集「{name}」を{count}件の用語で作成しました。", - "context.presets.hint": "プリセットをクリックして、専門用語の用語集を作成します。用語集セクションで管理できます。", - "context.glossary.manage": "用語集を管理", - "context.saved": "保存しました", - "context.savedDesc": "コンテキスト指示を保存しました。", - "admin.login.title": "管理画面", - "admin.login.required": "ログインが必要です", - "admin.login.password": "管理者パスワード", - "admin.login.connecting": "接続中...", - "admin.login.access": "管理画面にアクセス", - "admin.login.restricted": "管理者のみアクセス可能", - "admin.layout.checking": "認証を確認中...", - "admin.dashboard.title": "管理ダッシュボード", - "admin.dashboard.subtitle": "管理者コントロールパネル", - "admin.dashboard.refresh": "更新", - "admin.dashboard.refreshTooltip": "ダッシュボードデータを更新", - "admin.dashboard.config": "システム設定", - "admin.dashboard.maxFileSize": "最大ファイルサイズ:", - "admin.dashboard.translationService": "翻訳サービス:", - "admin.dashboard.formats": "対応形式:", - "admin.nav.dashboard": "Dashboard", - "admin.nav.users": "ユーザー", - "admin.nav.pricing": "料金と Stripe", - "admin.nav.providers": "プロバイダー", - "admin.nav.system": "システム", - "admin.nav.logs": "ログ", - "admin.users.title": "ユーザー管理", - "admin.users.subtitle": "ユーザーアカウントの表示と管理", - "admin.users.planUpdated": "プランが更新されました", - "admin.users.planChanged": "プランが「{plan}」に正常に変更されました。", - "admin.users.unknownError": "不明なエラー", - "admin.users.error": "エラー", - "admin.users.planUpdateError": "プランを更新できません:{message}", - "admin.users.noKeys": "キーなし", - "admin.users.noKeysDesc": "このユーザーにはアクティブなAPIキーがありません。", - "admin.users.keysRevoked": "キーが取り消されました", - "admin.users.keysRevokedDesc": "{count}件のAPIキーが正常に取り消されました。", - "admin.users.revokeError": "キーを取り消せません:{message}", - "admin.users.retry": "再試行", - "admin.system.title": "システム", - "admin.system.subtitle": "システム状態の監視とリソース管理", - "admin.system.quotas": "翻訳枠", - "admin.system.resetQuotas": "月間枠をリセット", - "admin.system.resetting": "リセット中...", - "admin.system.reset": "リセット", - "admin.system.allOperational": "すべてのシステムが正常稼働中", - "admin.system.issuesDetected": "システムに問題が検出されました", - "admin.system.waitingData": "データを待機中...", - "admin.system.purging": "パージ中...", - "admin.system.clean": "クリーン", - "admin.system.purge": "パージ", - "memento.title": "Momentoを発見", - "memento.slogan": "Momentoは単なるメモアプリではありません。6つのAIエージェントと高度なセマンティック検索を使用して、アイデアをリアルタイムで接続、分析、発展させるインテリジェントなエコシステムです。", - "memento.ctaFree": "無料で始める", - "memento.ctaMore": "詳しく見る", - "common.backToHome": "ホームに戻る", - "dashboard.topbar.interfaceLabel": "翻訳インターフェース", - "dashboard.topbar.premiumAccess": "プレミアムアクセス", - "landing.hero.contextEngine": "翻訳検出:HVACシステムの技術保守用語...", - "landing.hero.liveAnalysis": "リアルタイム分析", - "landing.hero.termsDetected": "件の用語を検出", - "landing.steps.process": "プロセス", - "landing.translate.newProject": "新規プロジェクト", - "landing.translate.title": "ドキュメントを翻訳", - "landing.translate.subtitle": "ファイルをインポートして翻訳先言語を選択", - "landing.translate.sourceDocument": "ソースドキュメント", - "landing.translate.configuration": "設定", - "landing.translate.sourceLang": "翻訳元言語", - "landing.translate.targetLang": "翻訳先言語", - "landing.translate.provider": "プロバイダー", - "landing.translate.startTranslation": "翻訳を開始", - "landing.translate.zeroRetention": "ゼロ保持", - "landing.translate.filesDeleted": "処理後にファイルを削除", - "landing.translate.dropHere": "ここにドラッグ&ドロップ", - "landing.translate.supportedFormats": "DOCX, XLSX, PPTX, PDFファイル対応", - "landing.translate.aiAnalysis": "AI分析アクティブ", - "landing.translate.processing": "処理中", - "landing.translate.preservingLayout": "レイアウトを保持しています", - "layout.nav.apiAccess": "API アクセス", - "layout.footer.terms": "利用規約", - "layout.footer.privacy": "プライバシー", - "fileUploader.uploadDocument": "ドキュメントをアップロード", - "fileUploader.uploadDesc": "ファイルをドラッグ&ドロップまたはクリックして選択 (Excel, Word, PowerPoint)", - "fileUploader.dropHere": "ここにファイルをドロップ…", - "fileUploader.dragAndDrop": "ここにドキュメントをドラッグ&ドロップ", - "fileUploader.orClickBrowse": "またはクリックして参照", - "fileUploader.preview": "プレビュー", - "fileUploader.translationOptions": "翻訳オプション", - "fileUploader.configureSettings": "翻訳設定を構成する", - "fileUploader.targetLanguage": "翻訳先の言語", - "fileUploader.selectLanguage": "言語を選択", - "fileUploader.translationProvider": "翻訳プロバイダー", - "fileUploader.selectProvider": "プロバイダーを選択", - "fileUploader.advancedOptions": "詳細オプション", - "fileUploader.translateImages": "画像を翻訳", - "fileUploader.translating": "翻訳中…", - "fileUploader.translateDocument": "ドキュメントを翻訳", - "fileUploader.processing": "処理中…", - "fileUploader.translationError": "翻訳エラー", - "fileUploader.translationComplete": "翻訳完了!", - "fileUploader.translationCompleteDesc": "書式をすべて保持したまま、ドキュメントの翻訳が完了しました。", - "fileUploader.download": "翻訳済みドキュメントをダウンロード", - "fileUploader.webgpuUnsupported": "このブラウザは WebGPU に対応していません。Chrome 113+ または Edge 113+ を使用してください。", - "fileUploader.webllmNotLoaded": "WebLLM モデルが読み込まれていません。設定 > 翻訳サービスからモデルを読み込んでください。", - "fileUploader.extracting": "ドキュメントからテキストを抽出中…", - "fileUploader.noTranslatable": "ドキュメントに翻訳可能なテキストが見つかりません", - "fileUploader.foundTexts": "{count} 件の翻訳対象テキストが見つかりました", - "fileUploader.translatingItem": "翻訳中 {current}/{total}: 「{preview}」", - "fileUploader.reconstructing": "ドキュメントを再構築中…", - "fileUploader.translatingLocally": "WebLLM でローカル翻訳中…", - "checkout.activating": "有効化中…", - "checkout.activatingDesc": "サブスクリプションを更新中です。しばらくお待ちください。", - "checkout.paymentConfirmed": "支払いを確認しました!", - "checkout.subscriptionActivated": "サブスクリプションが有効化されました!", - "checkout.planActivated": "{plan} プランが有効化されました!", - "checkout.redirectingToProfile": "プロフィールにリダイレクト中…", - "checkout.paymentReceived": "支払いを受領しました", - "checkout.redirecting": "リダイレクト中…", - "checkout.syncError": "同期エラー", - "checkout.networkError": "ネットワークエラー。お支払いは確認済みです — プロフィールを再読み込みしてください。", - "dashboard.checkoutSyncError": "支払いの同期エラー。", - "dashboard.networkRefresh": "ネットワークエラー。ページを更新してください。", - "dashboard.continueToTranslate": "翻訳に進む", - "langSelector.search": "検索…", - "langSelector.noResults": "結果なし", - "langSelector.source": "翻訳元", - "langSelector.target": "翻訳先", - "langSelector.swap": "入れ替え", - "translateComplete.highQuality": "高品質", - "translateComplete.segments": "セグメント", - "translateComplete.characters": "文字", - "translateComplete.confidence": "信頼度", - "providerTheme.deepseek.badge": "エッセンシャル", - "providerTheme.deepseek.subBadge": "技術とエコ", - "providerTheme.deepseek.desc": "超高精度で経済的な翻訳。技術文書やコードに最適。", - "providerTheme.openai.badge": "プレミアム", - "providerTheme.openai.subBadge": "高忠実度", - "providerTheme.openai.desc": "AIの世界標準。テキストの一貫性を最大化し、スタイルを厳格に守ります。", - "providerTheme.minimax.badge": "上級", - "providerTheme.minimax.subBadge": "パフォーマンス", - "providerTheme.minimax.desc": "驚異的な実行速度と複雑な構造の優れた理解。", - "providerTheme.openrouter.badge": "エクスプレス", - "providerTheme.openrouter.subBadge": "マルチモデル", - "providerTheme.openrouter.desc": "翻訳に最適化された最高のオープンソースモデルへの統一アクセス。", - "providerTheme.openrouter_premium.badge": "ウルトラ", - "providerTheme.openrouter_premium.subBadge": "最大コンテキスト", - "providerTheme.openrouter_premium.desc": "GPT-4o、Claude Sonnet 4.6 などの最先端モデルによる長文支援。", - "providerTheme.zai.badge": "特化型", - "providerTheme.zai.subBadge": "金融と法律", - "providerTheme.zai.desc": "要求の厳しいビジネス用語 (法務、金融) 向けに微調整されたモデル。", - "providerTheme.default.badge": "モダン", - "providerTheme.default.subBadge": "AI 推論", - "providerTheme.default.desc": "大規模言語モデル (LLM) による、高度な意味分析を伴う翻訳。", - "providerTheme.classic.google.label": "Google 翻訳", - "providerTheme.classic.google.desc": "130 以上の言語に対応する超高速翻訳。一般的なフローにおすすめです。", - "providerTheme.classic.deepl.label": "DeepL Pro", - "providerTheme.classic.deepl.desc": "流暢さと自然な表現で知られる高精度翻訳。", - "providerTheme.classic.google_cloud.label": "Google Cloud API", - "providerTheme.classic.google_cloud.desc": "大量ドキュメント処理に最適化されたプロフェッショナル向けクラウドエンジン。", - "providerSelector.noClassic": "利用可能な標準翻訳者はありません。", - "providerSelector.noLlm": "AI モデルが設定されていません。", - "providerSelector.costOne": "料金: 1 ページあたり 1 クレジット", - "providerSelector.costFive": "料金: 1 ページあたり 5 クレジット (プレミアム係数)", - "providerSelector.unlockContextual": "ドキュメント全体の高品質コンテキスト翻訳をアンロック。", - "translate.header.processing": "処理中", - "translate.header.aiActive": "AI 分析アクティブ", - "translate.header.aiActiveDesc": "レイアウトはコンテキストエンジンによって保持されています。", - "translate.header.completed": "完了", - "translate.header.completedTitle": "翻訳完了", - "translate.header.proSpace": "Pro スペース", - "translate.header.translateDoc": "ドキュメントを翻訳", - "translate.header.translateDocDesc": "超高忠実度の翻訳エンジンで元のレイアウトを保持します。", - "translate.upload.nativeFormat": "ネイティブ形式", - "translate.fileType.word": "Word (.docx)", - "translate.fileType.excel": "Excel (.xlsx)", - "translate.fileType.slides": "スライド (.pptx)", - "translate.fileType.pdf": "PDF (.pdf)", - "translate.startTranslation": "翻訳を開始", - "translate.submit": "送信中…", - "translate.chooseTargetLang": "翻訳先の言語を選択してください", - "translate.pleaseLoadFile": "まずファイルをアップロードしてください", - "translate.contextEngineActive": "コンテキストエンジン作動中", - "translate.phase1": "フェーズ 1: 初期化", - "translate.phase2": "フェーズ 2: コンテキスト再構築", - "translate.stat.segments": "セグメント", - "translate.stat.precision": "精度", - "translate.stat.speedLabel": "速度", - "translate.stat.turbo": "ターボ", - "translate.stat.time": "時間", - "translate.complete.masterQuality": "✓ マスター品質", - "translate.download": "ダウンロード", - "translate.newTranslation": "+ 新しい翻訳", - "translate.failedTitle": "翻訳エラー", - "translate.retry": "再試行", - "translate.uploadAnother": "別のファイルをアップロード", - "translate.monitor": "AI モニター", - "translate.summary": "サマリー", - "translate.cancelProcess": "⟳ プロセスをキャンセル", - "translate.layoutIntegrity": "レイアウト整合性", - "translate.secureHundred": "100% 安全", - "translate.okHundred": "100% OK", - "translate.preserveLayout": "レイアウトを保持", - "translate.preserveLayoutDesc": "レイアウトを保持", - "translate.textOnly": "テキストのみ", - "translate.textOnlyDesc": "テキストのみの高速翻訳", - "translate.unavailableStandard": "標準モードでは利用できません (AI のみ)", - "apiKeys.noKeysGenerated": "キーは生成されていません", - "apiKeys.copied": "コピーしました!", - "services.fallback.google.label": "Google 翻訳", - "services.fallback.google.desc": "高速翻訳、130 以上の言語", - "settings.formats.excel.name": "Excel", - "settings.formats.word.name": "Word", - "settings.formats.powerpoint.name": "PowerPoint", - "pricing.dashboard": "ダッシュボード", - "pricing.okSymbol": "✓", - "pricing.errSymbol": "✕", - }, - // ═══════════════════════════════════════════════════════════════ - // KOREAN (ko) - // ═══════════════════════════════════════════════════════════════ - ko: { - "auth.brandName": "Wordly", - "dashboard.nav.translate": "번역", - "dashboard.nav.profile": "내 프로필", - "dashboard.nav.settings": "설정", - "dashboard.nav.context": "컨텍스트", - "dashboard.nav.services": "서비스", - "dashboard.nav.apiKeys": "API 키", - "dashboard.nav.glossaries": "용어집", - "dashboard.header.title": "대시보드", - "dashboard.header.subtitle": "번역 관리", - "dashboard.header.toggleMenu": "메뉴", - "dashboard.header.profileTitle": "내 프로필", - "dashboard.sidebar.theme": "테마", - "dashboard.sidebar.signOut": "로그아웃", - "dashboard.sidebar.backHome": "홈으로 돌아가기", - "dashboard.sidebar.upgradeToPro": "Pro로 업그레이드 →", - "cookieConsent.title": "Wordly 쿠키", - "cookieConsent.description": "앱 작동에 필요한 필수 쿠키를 사용합니다(세션, 보안, 언어). 허락하시면 트래픽 측정 및 제품 개선을 위한 선택적 쿠키도 사용합니다.", - "cookieConsent.acceptAll": "모두 허용", - "cookieConsent.essentialOnly": "필수만", - "cookieConsent.learnMore": "자세히 보기", - "landing.nav.why": "왜 우리인가요?", - "landing.nav.formats": "지원 형식", - "landing.nav.pricing": "요금제", - "landing.nav.login": "로그인", - "landing.nav.startFree": "무료 시작", - "landing.hero.tag": "전문 문서 AI", - "landing.hero.titleLine1": "문서를 번역하세요.", - "landing.hero.titleLine2": "서식은 완벽하게 유지.", - "landing.hero.description": "SmartArt, 차트, 목차, 도형 및 복잡한 레이아웃을 원본 그대로 보존하는 유일한 번역기입니다.", - "landing.hero.ctaMain": "무료 시작 — 월 2개 문서", - "landing.hero.ctaSec": "플랜 보기", - "landing.hero.deleted": "파일은 60분 후 삭제", - "landing.hero.noHidden": "숨겨진 비용 없음", - "landing.hero.preview": "결제 전 미리보기", - "landing.hero.formattedOk": "서식 OK", - "landing.hero.aiActive": "AI 번역 활성", - "landing.steps.title": "어떻게 작동하나요?", - "landing.steps.subtitle": "3단계. 서식 손실 제로.", - "landing.steps.step1.num": "01", - "landing.steps.step1.title": "파일 업로드", - "landing.steps.step1.desc": "Excel, Word, PowerPoint 또는 PDF 문서를 드래그 앤 드롭하세요.", - "landing.steps.step2.num": "02", - "landing.steps.step2.title": "언어 및 엔진 선택", - "landing.steps.step2.desc": "대상 언어와 엔진을 선택하세요 — 클래식 또는 컨텍스트 인식 AI.", - "landing.steps.step3.num": "03", - "landing.steps.step3.title": "결과 다운로드", - "landing.steps.step3.desc": "원본과 동일한 서식의 번역 문서를 받으세요.", - "landing.features.tag": "AI 번역 엔진", - "landing.features.title": "당신의 전문성을 이해하는 번역", - "landing.features.description": "AI 모델이 컨텍스트를 분석하고, 전문 용어를 존중하며, 이미지 내 텍스트까지 번역합니다.", - "landing.features.context.title": "산업 컨텍스트", - "landing.features.context.desc": "분야를 설명하면 일반적인 번역이 아닌 맞춤형 번역을 받습니다.", - "landing.features.glossary.title": "산업 용어집", - "landing.features.glossary.desc": "전문 용어를 정의하세요. CTA는 'Call To Action'이 아닌 '공기처리장치'로 유지됩니다.", - "landing.features.vision.title": "이미지 인식", - "landing.features.vision.desc": "이미지, 다이어그램, 차트에 포함된 텍스트를 감지하고 번역합니다.", - "landing.features.demo.source": "원문 (FR)", - "landing.features.demo.google": "Google 번역", - "landing.features.demo.ours": "당사 AI", - "landing.layout.title": "당신의 서식,", - "landing.layout.title2": "완벽하게 보존", - "landing.layout.subtitle": "다른 번역기는 레이아웃을 망칩니다. 우리는 다릅니다.", - "landing.layout.p1.title": "SmartArt 및 다이어그램", - "landing.layout.p1.desc": "조직도, 순서도, 계층도 — 모두 동일하게 번역.", - "landing.layout.p2.title": "목차", - "landing.layout.p2.desc": "목차 항목, 페이지 번호, 상호 참조가 올바르게 업데이트됩니다.", - "landing.layout.p3.title": "차트 및 그래프", - "landing.layout.p3.desc": "제목, 축 레이블, 범례 및 시리즈 이름 — 모두 번역됩니다.", - "landing.layout.p4.title": "도형 및 텍스트 상자", - "landing.layout.p4.desc": "사각형, 둥근 블록, 설명선 — 모든 곳에 로컬라이징.", - "landing.layout.p5.title": "머리글 및 바닥글", - "landing.layout.p5.desc": "머리글, 바닥글, 각주가 절대 누락되지 않습니다.", - "landing.layout.p6.title": "130개 이상의 언어", - "landing.layout.p6.desc": "Google 번역, DeepL 및 전문급 AI 엔진.", - "landing.formats.title": "모든 형식,", - "landing.formats.title2": "모든 요소", - "landing.formats.subtitle": "다른 곳에서 놓치는 부분까지 번역합니다. 비즈니스에 흠잡을 데 없는 문서를.", - "landing.formats.word.name": "Word", - "landing.formats.word.i1": "단락 및 제목", - "landing.formats.word.i2": "표 및 차트", - "landing.formats.word.i3": "SmartArt 다이어그램", - "landing.formats.word.i4": "목차", - "landing.formats.word.i5": "머리글 및 바닥글", - "landing.formats.word.i6": "도형 및 텍스트 상자", - "landing.formats.word.i7": "각주 및 미주", - "landing.formats.excel.name": "Excel", - "landing.formats.excel.i1": "셀 값", - "landing.formats.excel.i2": "시트 이름", - "landing.formats.excel.i3": "차트 및 레이블", - "landing.formats.excel.i4": "머리글 및 바닥글", - "landing.formats.excel.i5": "병합된 셀 유지", - "landing.formats.pptx.name": "PowerPoint", - "landing.formats.pptx.i1": "슬라이드 텍스트 및 메모", - "landing.formats.pptx.i2": "차트 및 다이어그램", - "landing.formats.pptx.i3": "도형 및 텍스트 상자", - "landing.formats.pptx.i4": "마스터 레이아웃", - "landing.formats.pptx.i5": "애니메이션 유지", - "landing.formats.pdf.name": "PDF", - "landing.formats.pdf.i1": "텍스트 기반 PDF", - "landing.formats.pdf.i2": "레이아웃 유지", - "landing.formats.pdf.i3": "이미지 제자리 유지", - "landing.formats.pdf.i4": "표 유지", - "landing.formats.pdf.i5": "DOCX 또는 PDF로 출력", - "landing.pricing.title": "간단하고 투명한 가격", - "landing.pricing.subtitle": "보이는 가격이 지불하실 금액입니다. 숨겨진 비용 없음.", - "landing.pricing.monthly": "월간", - "landing.pricing.annual": "연간", - "landing.pricing.bestValue": "가장 인기", - "landing.pricing.month": "/월", - "landing.pricing.footer": "표시된 가격이 지불하실 금액입니다. 번역 후 추가 비용 없음.", - "landing.pricing.starter.name": "Starter", - "landing.pricing.starter.desc": "개인 및 소규모 프로젝트용", - "landing.pricing.starter.f1": "월 50개 문서", - "landing.pricing.starter.f2": "문서당 최대 50페이지", - "landing.pricing.starter.f3": "Google 번역 + DeepL", - "landing.pricing.starter.f4": "최대 10 MB 파일", - "landing.pricing.starter.cta": "시작하기", - "landing.pricing.pro.name": "Pro", - "landing.pricing.pro.desc": "전문가용", - "landing.pricing.pro.f1": "월 200개 문서", - "landing.pricing.pro.f2": "문서당 최대 200페이지", - "landing.pricing.pro.f3": "AI 번역", - "landing.pricing.pro.f4": "Google + DeepL 포함", - "landing.pricing.pro.f5": "맞춤 용어집 및 프롬프트", - "landing.pricing.pro.f6": "우선 지원", - "landing.pricing.pro.cta": "Pro 체험", - "landing.pricing.business.name": "비즈니스", - "landing.pricing.business.desc": "대용량이 필요한 팀용", - "landing.pricing.business.f1": "월 1,000개 문서", - "landing.pricing.business.f2": "문서당 최대 500페이지", - "landing.pricing.business.f3": "프리미엄 AI (Claude)", - "landing.pricing.business.f4": "모든 제공자 + API", - "landing.pricing.business.f5": "웹훅 및 자동화", - "landing.pricing.business.f6": "팀 시트 5석", - "landing.pricing.business.cta": "문의하기", - "landing.cta.title": "30초 만에 번역 시작", - "landing.cta.subtitle": "신용카드 불필요. 지금 무료로 체험하고 다국어 문서에 새 생명을 불어넣으세요.", - "landing.cta.button": "무료 계정 만들기", - "landing.cta.secure": "AES-256 암호화로 보호", - "landing.footer.desc": "지능형 문서 번역 전문. 레이아웃의 예술과 컨텍스트 AI의 과학을 융합합니다.", - "landing.footer.product": "제품", - "landing.footer.resources": "리소스", - "landing.footer.legal": "법적 고지", - "landing.footer.rights": "© 2026 Wordly.art — All rights reserved.", - "dashboard.translate.pageTitle": "문서 번역", - "dashboard.translate.pageSubtitle": "파일을 가져오고 대상 언어를 선택하세요", - "dashboard.translate.errorNotificationTitle": "오류", - "dashboard.translate.dropzone.uploadAria": "파일 드롭 영역", - "dashboard.translate.dropzone.title": "여기에 파일을 드래그 앤 드롭하세요", - "dashboard.translate.dropzone.subtitle": "또는 클릭하여 선택 (DOCX, XLSX, PPTX, PDF)", - "dashboard.translate.dropzone.replaceFile": "파일 교체", - "dashboard.translate.language.source": "원본 언어", - "dashboard.translate.language.target": "대상 언어", - "dashboard.translate.language.loading": "언어 로딩 중…", - "dashboard.translate.language.autoDetect": "자동 감지", - "dashboard.translate.language.selectPlaceholder": "선택…", - "dashboard.translate.language.loadErrorPrefix": "언어 로딩 실패", - "dashboard.translate.provider.loading": "제공업체 로딩 중…", - "dashboard.translate.provider.noneConfigured": "구성된 제공업체 없음", - "dashboard.translate.provider.modelTitle": "모델", - "dashboard.translate.provider.sectionTitle": "제공업체", - "dashboard.translate.provider.llmDivider": "AI · 문맥 인식", - "dashboard.translate.provider.llmDividerPro": "AI · 문맥 인식 (Pro)", - "dashboard.translate.provider.upgrade": "Pro로 업그레이드", - "dashboard.translate.provider.upgradeSuffix": "AI 번역 잠금 해제", - "dashboard.translate.trust.zeroRetention": "데이터 미보관", - "dashboard.translate.trust.deletedAfter": "처리 후 파일 삭제", - "dashboard.translate.actions.uploading": "업로드 중…", - "dashboard.translate.actions.translate": "번역", - "dashboard.translate.actions.filePrefix": "파일: ", - "dashboard.translate.actions.cancel": "취소", - "dashboard.translate.actions.tryAgain": "다시 시도", - "dashboard.translate.steps.uploading": "파일 업로드 중…", - "dashboard.translate.steps.starting": "번역 시작 중…", - "dashboard.translate.complete.title": "번역 완료!", - "dashboard.translate.complete.descNamed": "파일 {name}의 번역이 성공적으로 완료되었습니다.", - "dashboard.translate.complete.descGeneric": "파일의 번역이 성공적으로 완료되었습니다.", - "dashboard.translate.complete.downloading": "다운로드 중…", - "dashboard.translate.complete.download": "다운로드", - "dashboard.translate.complete.newTranslation": "새 번역", - "dashboard.translate.complete.toastOkTitle": "성공", - "dashboard.translate.complete.toastOkDesc": "{name} 다운로드가 완료되었습니다.", - "dashboard.translate.complete.toastFailTitle": "실패", - "dashboard.translate.complete.toastFailDesc": "번역에 실패했습니다. 다시 시도해 주세요.", - "dashboard.translate.sourceDocument": "원본 문서", - "dashboard.translate.configuration": "설정", - "dashboard.translate.translating": "번역 진행 중", - "dashboard.translate.liveMonitor": "실시간 모니터", - "dashboard.translate.summary": "요약", - "dashboard.translate.engine": "엔진", - "dashboard.translate.confidence": "신뢰도", - "dashboard.translate.cancel": "취소", - "dashboard.translate.segments": "세그먼트", - "dashboard.translate.characters": "문자", - "dashboard.translate.elapsed": "경과", - "dashboard.translate.segPerMin": "세그/분", - "dashboard.translate.highQuality": "고품질", - "dashboard.translate.quality": "품질", - "dashboard.translate.completed": "번역 완료", - "dashboard.translate.replace": "교체", - "dashboard.translate.pdfMode.title": "PDF 번역 모드", - "dashboard.translate.pdfMode.preserveLayout": "레이아웃 유지", - "dashboard.translate.pdfMode.textOnly": "텍스트만", - "dashboard.translate.pdfMode.preserveLayoutDesc": "이미지, 표 및 서식을 유지합니다. 간단한 PDF에 적합.", - "dashboard.translate.pdfMode.textOnlyDesc": "모든 텍스트를 완벽하게 번역합니다. 깔끔한 출력, 레이아웃 문제 없음.", - "dashboard.translate.pipeline.upload": "업로드", - "dashboard.translate.pipeline.analyze": "분석", - "dashboard.translate.pipeline.translate": "번역", - "dashboard.translate.pipeline.rebuild": "재구성", - "dashboard.translate.pipeline.finalize": "완료", - "dashboard.translate.progress.processingFallback": "처리 중…", - "dashboard.translate.progress.connectionLost": "연결이 끊어졌습니다. 재시도 중…", - "dashboard.translate.progress.failedTitle": "번역 실패", - "dashboard.translate.error.unexpected": "예기치 않은 오류가 발생했습니다. 다시 시도해 주세요.", - "dashboard.translate.error.noResult": "번역 결과가 없습니다. 문서에 텍스트가 포함되어 있는지 확인하고 다시 시도하거나 다른 엔진을 선택하세요.", - "dashboard.translate.error.apiKey": "API 키가 유효하지 않거나 없습니다. 관리자에게 문의하여 API 키를 설정하세요.", - "dashboard.translate.error.quota": "사용 한도에 도달했습니다. 몇 분 후에 다시 시도하거나 다른 엔진을 선택하세요.", - "dashboard.translate.error.timeout": "번역 서비스 연결 시간이 초과되었습니다. 네트워크를 확인하고 다시 시도하세요.", - "dashboard.translate.error.sessionExpired": "세션이 만료되었습니다. 다시 시도를 클릭하여 번역을 재시작하세요.", - "dashboard.translate.error.empty": "문서가 비어 있거나 번역 가능한 텍스트가 없습니다 (스캔 PDF 이미지?).", - "dashboard.translate.error.unsupported": "지원되지 않는 파일 형식이거나 손상된 파일입니다.", - "dashboard.translate.error.connection": "연결이 끊겼습니다. 네트워크를 확인하고 다시 시도하세요.", - "dashboard.translate.error.generic": "번역 실패: {detail}", - "dashboard.translate.error.title": "번역 실패", - "dashboard.translate.retry": "번역 다시 시도", - "dashboard.translate.newFile": "새 파일", - "dashboard.translate.modeAI": "AI 모드", - "dashboard.translate.modeClassic": "클래식 모드", - "dashboard.translate.glossaryLLMHint": "AI 모드에서 용어집 사용 가능", - "dashboard.translate.submitting": "제출 중...", - "dashboard.translate.submit": "번역 시작", - "dashboard.translate.noFile": "먼저 파일을 업로드하세요", - "dashboard.translate.noTargetLang": "대상 언어를 선택하세요", - "glossaries.yourGlossaries": "내 용어집", - "glossaries.title": "용어집 및 컨텍스트", - "glossaries.description": "용어집과 컨텍스트 지침을 관리하여 더 정확한 번역을하세요.", - "glossaries.createNew": "새로 만들기", - "glossaries.empty": "용어집이 없습니다", - "glossaries.emptyDesc": "첫 번째 용어집을 만들거나 위에서 전문 프리셋을 로드하세요", - "glossaries.defineTerms": "용어", - "glossaries.aboutTitle": "용어집 정보", - "glossaries.aboutDesc": "용어집을 사용하면 특정 용어에 대한 정확한 번역을 정의할 수 있습니다. 번역 시 용어집 용어가 사용되어 일관되고 정확한 번역이 보장됩니다.", - "glossaries.aboutFormat": "각 용어에는 원본 단어와 여러 언어의 번역이 있습니다. 번역 페이지에서 용어집을 선택하여 적용하세요.", - "glossaries.toast.created": "용어집 생성됨", - "glossaries.toast.createdDesc": "용어집 \"{name}\"이(가) 생성되었습니다.", - "glossaries.toast.imported": "용어집 가져오기 완료", - "glossaries.toast.importedDesc": "용어집 \"{name}\"을(를) 가져왔습니다.", - "glossaries.toast.updated": "용어집 업데이트됨", - "glossaries.toast.updatedDesc": "용어집 \"{name}\"이(가) 업데이트되었습니다.", - "glossaries.toast.deleted": "용어집 삭제됨", - "glossaries.toast.deletedDesc": "용어집이 삭제되었습니다.", - "glossaries.toast.error": "오류", - "glossaries.toast.errorCreate": "용어집 생성 실패", - "glossaries.toast.errorImport": "용어집 가져오기 실패", - "glossaries.toast.errorUpdate": "용어집 업데이트 실패", - "glossaries.toast.errorDelete": "용어집 삭제 실패", - "glossaries.dialog.title": "새 용어집", - "glossaries.dialog.description": "번역을 위한 용어집을 만드세요", - "glossaries.dialog.nameLabel": "이름", - "glossaries.dialog.namePlaceholder": "내 용어집", - "glossaries.dialog.tabTemplates": "템플릿", - "glossaries.dialog.tabFile": "파일", - "glossaries.dialog.tabManual": "수동", - "glossaries.dialog.cancel": "취소", - "glossaries.dialog.creating": "생성 중…", - "glossaries.dialog.importing": "가져오는 중…", - "glossaries.dialog.importBtn": "가져오기", - "glossaries.dialog.selectPrompt": "선택", - "glossaries.dialog.createBtn": "생성", - "glossaries.dialog.createEmpty": "빈 용어집 생성", - "glossaries.dialog.terms": "개 용어", - "glossaries.dialog.templatesDesc": "미리 정의된 템플릿을 선택하세요", - "glossaries.dialog.templatesEmpty": "사용 가능한 템플릿이 없습니다", - "glossaries.dialog.dropTitle": "CSV 파일을 여기로 드래그하세요", - "glossaries.dialog.dropOr": "또는", - "glossaries.dialog.dropFormats": "CSV, TSV, TXT", - "glossaries.termEditor.addTerm": "용어 추가", - "glossaries.termEditor.maxReached": "용어집당 최대 {max}개 용어에 도달했습니다.", - "glossaries.dialog.formatTitle": "형식", - "glossaries.dialog.formatDesc": "원본,대상 (한 줄에 하나씩)", - "glossaries.dialog.formatNote": "헤더가 감지되면 첫 줄은 건너뜁니다", - "glossaries.dialog.errorFormat": "지원되지 않는 형식", - "glossaries.dialog.errorSize": "파일이 너무 큽니다", - "glossaries.dialog.errorEmpty": "빈 파일", - "glossaries.dialog.errorRead": "읽기 오류", - "glossaries.dialog.parsing": "구문 분석 중…", - "glossaries.dialog.termsImported": "개 용어 가져옴", - "glossaries.dialog.changeFile": "파일 변경", - "glossaries.dialog.retry": "다시 시도", - "glossaries.edit.title": "Modifier le glossaire", - "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", - "glossaries.edit.nameLabel": "Nom du glossaire", - "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", - "glossaries.edit.sourceLang": "Langue source", - "glossaries.edit.targetLang": "Langue cible", - "glossaries.edit.termsLabel": "Termes ({count} valides)", - "glossaries.edit.exportCsv": "Exporter CSV", - "glossaries.edit.importCsv": "Importer CSV", - "glossaries.edit.cancel": "Annuler", - "glossaries.edit.saving": "Enregistrement...", - "glossaries.edit.saveChanges": "Enregistrer les modifications", - "glossaries.edit.importFailedTitle": "Échec de l'importation", - "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", - "glossaries.edit.importSuccessTitle": "Importation réussie", - "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", - "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", - "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", - "glossaries.delete.title": "Supprimer le glossaire", - "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", - "glossaries.delete.warning": "Cette action est irréversible", - "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", - "glossaries.delete.cancel": "Annuler", - "glossaries.delete.deleting": "Suppression...", - "glossaries.delete.deleteBtn": "Supprimer", - "glossaries.upgrade.title": "Glossaires", - "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", - "glossaries.upgrade.feature1": "Créez plusieurs glossaires", - "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", - "glossaries.upgrade.feature3": "Importez/exportez via CSV", - "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", - "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", - "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", - "glossaries.upgrade.proLabel": "Pro", - "glossaries.upgrade.upgradeBtn": "Passer à Pro", - "glossaries.loading": "Chargement...", - "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", - "glossaries.howItWorks.step1Title": "Configurez ici", - "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", - "glossaries.howItWorks.step2Title": "Activez dans Traduire", - "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", - "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", - "glossaries.howItWorks.goToTranslate": "Aller à Traduire", - "glossaries.status.unsaved": "Non enregistré", - "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", - "glossaries.status.inactive": "Inactif", - "glossaries.instructions.whatForBold": "À quoi ça sert ?", - "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", - "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", - "glossaries.instructions.charCount": "{count} caractères", - "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", - "glossaries.instructions.clearAll": "Tout effacer", - "glossaries.instructions.saving": "Enregistrement…", - "glossaries.instructions.saved": "Enregistré", - "glossaries.presets.whatForBold": "À quoi ça sert ?", - "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", - "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", - "glossaries.presets.creating": "Création…", - "glossaries.presets.alreadyImported": "Déjà importé", - "glossaries.presets.it.title": "IT / Logiciel", - "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", - "glossaries.presets.legal.title": "Juridique / Contrats", - "glossaries.presets.legal.desc": "Droit des affaires, contentieux", - "glossaries.presets.medical.title": "Médical / Santé", - "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", - "glossaries.presets.finance.title": "Finance / Comptabilité", - "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", - "glossaries.presets.marketing.title": "Marketing / Publicité", - "glossaries.presets.marketing.desc": "Digital, branding, analytics", - "glossaries.presets.hr.title": "RH / Ressources Humaines", - "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", - "glossaries.presets.scientific.title": "Scientifique / Recherche", - "glossaries.presets.scientific.desc": "Publications, thèses, articles", - "glossaries.presets.ecommerce.title": "E-commerce / Vente", - "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", - "glossaries.grid.title": "Vos", - "glossaries.grid.titleHighlight": "glossaires", - "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", - "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", - "glossaries.grid.activeTranslation": "Traduction active :", - "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", - "glossaries.badge.compatible": "Compatible", - "glossaries.badge.otherTarget": "Autre cible", - "glossaries.card.editTerms": "Modifier les termes", - "glossaries.card.created": "생성됨", - "glossaries.card.term": "용어", - "glossaries.card.delete": "Supprimer", - "glossaries.grid.searchPlaceholder": "Search a glossary…", - "glossaries.grid.noResults": "No results for this search.", - "glossaries.detail.backToList": "Back to glossaries", - "glossaries.detail.save": "Save", - "glossaries.detail.savedTitle": "Saved", - "glossaries.detail.savedDesc": "The glossary has been updated.", - "glossaries.detail.settingsTitle": "Settings", - "glossaries.detail.sourceLang": "Source language", - "glossaries.detail.targetLang": "Target language", - "glossaries.detail.termsTitle": "Terms", - "glossaries.detail.terms": "terms", - "glossaries.detail.searchTerms": "Filter…", - "glossaries.detail.noTerms": "No terms yet.", - "glossaries.detail.addFirstTerm": "Add the first term", - "glossaries.detail.addTerm": "Add a term", - "glossaries.detail.maxReached": "Maximum limit reached", - "glossaries.detail.source": "Source", - "glossaries.detail.target": "Target", - "glossaries.detail.sourcePlaceholder": "source term", - "glossaries.detail.targetPlaceholder": "target term", - "glossaries.detail.csvTitle": "CSV", - "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", - "glossaries.detail.export": "Export", - "glossaries.detail.import": "Import", - "glossaries.detail.dangerTitle": "Danger zone", - "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", - "glossaries.detail.deleteGlossary": "Delete this glossary", - "glossaries.detail.confirmDelete": "Confirm deletion?", - "glossaries.detail.confirm": "Confirm", - "glossaries.detail.cancel": "Cancel", - "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", - "glossaries.detail.sourceLocked": "fixed", - "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", - "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", - "glossaries.detail.notFoundTitle": "Glossary not found", - "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", - "glossaries.detail.maxTermsTitle": "Limit reached", - "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", - "glossaries.detail.importEmptyTitle": "Empty file", - "glossaries.detail.importEmptyDesc": "No terms detected in this file.", - "glossaries.detail.importedTitle": "Imported", - "glossaries.detail.importedDesc": "{count} terms imported.", - "glossaries.detail.importErrorTitle": "Read error", - "glossaries.detail.importErrorDesc": "Unable to read the file.", - "apiKeys.webhook.title": "Intégration Webhook", - "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", - "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", - "apiKeys.webhook.codeParam": "webhook_url", - "translate.mode.label": "Mode de traduction", - "translate.mode.classic": "Classique", - "translate.mode.classicDesc": "Rapide", - "translate.mode.proLlm": "Pro LLM", - "translate.mode.proLlmDesc": "Contextuel", - "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", - "translate.mode.upgradeLink": "Passer à Pro", - "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", - "pricing.nav.back": "뒤로", - "pricing.nav.home": "홈", - "pricing.nav.mySubscription": "내 구독", - "pricing.header.badge": "AI 모델 업데이트 — 2026년 3월", - "pricing.header.title": "모든 요구에 맞는 플랜", - "pricing.header.subtitle": "원본 레이아웃을 유지하면서 Word, Excel, PowerPoint 문서를 번역하세요. API 키 불필요.", - "pricing.billing.monthly": "월간", - "pricing.billing.yearly": "연간", - "pricing.plans.free.name": "무료", - "pricing.plans.starter.name": "Starter", - "pricing.plans.pro.name": "Pro", - "pricing.plans.business.name": "Business", - "pricing.plans.enterprise.name": "Enterprise", - "pricing.plans.free.description": "앱을 체험하기에 완벽", - "pricing.plans.starter.description": "개인 및 소규모 프로젝트용", - "pricing.plans.pro.description": "전문가 및 성장 중인 팀용", - "pricing.plans.business.description": "팀 및 조직용", - "pricing.plans.enterprise.description": "대규모 조직을 위한 맞춤 솔루션", - "pricing.plans.pro.highlight": "가장 인기", - "pricing.plans.pro.badge": "인기", - "pricing.plans.enterprise.badge": "문의 필요", - "pricing.plans.free.feat1": "월 5개 문서", - "pricing.plans.free.feat2": "문서당 최대 15페이지", - "pricing.plans.free.feat3": "Google 번역 포함", - "pricing.plans.free.feat4": "모든 언어 (130+)", - "pricing.plans.free.feat5": "커뮤니티 지원", - "pricing.plans.starter.feat1": "월 50개 문서", - "pricing.plans.starter.feat2": "문서당 최대 50페이지", - "pricing.plans.starter.feat3": "Google 번역 + DeepL", - "pricing.plans.starter.feat4": "최대 10 MB 파일", - "pricing.plans.starter.feat5": "이메일 지원", - "pricing.plans.starter.feat6": "30일 기록", - "pricing.plans.pro.feat1": "월 200개 문서", - "pricing.plans.pro.feat2": "문서당 최대 200페이지", - "pricing.plans.pro.feat3": "Essential AI 번역", - "pricing.plans.pro.feat4": "Google 번역 + DeepL", - "pricing.plans.pro.feat5": "최대 25 MB 파일", - "pricing.plans.pro.feat6": "사용자 지정 용어집", - "pricing.plans.pro.feat7": "우선 지원", - "pricing.plans.pro.feat8": "90일 기록", - "pricing.plans.business.feat1": "월 1,000개 문서", - "pricing.plans.business.feat2": "문서당 최대 500페이지", - "pricing.plans.business.feat3": "에센셜 + 프리미엄 AI (Claude Haiku)", - "pricing.plans.business.feat4": "모든 번역 제공업체", - "pricing.plans.business.feat5": "최대 50 MB 파일", - "pricing.plans.business.feat6": "API 액세스 (월 10,000회 호출)", - "pricing.plans.business.feat7": "알림 웹훅", - "pricing.plans.business.feat8": "전담 지원", - "pricing.plans.business.feat9": "1년 기록", - "pricing.plans.business.feat10": "고급 분석", - "pricing.plans.enterprise.feat1": "무제한 문서", - "pricing.plans.enterprise.feat2": "모든 AI 모델 (GPT-5, Claude Opus 4.6…)", - "pricing.plans.enterprise.feat3": "온프레미스 또는 전용 클라우드 배포", - "pricing.plans.enterprise.feat4": "99.9% SLA 보장", - "pricing.plans.enterprise.feat5": "24/7 전담 지원", - "pricing.plans.enterprise.feat6": "화이트라벨", - "pricing.plans.enterprise.feat7": "무제한 팀", - "pricing.plans.enterprise.feat8": "맞춤 연동", - "pricing.card.onRequest": "문의 필요", - "pricing.card.free": "무료", - "pricing.card.perMonth": "/월", - "pricing.card.billedYearly": "연 {price} € 청구", - "pricing.card.documents": "문서", - "pricing.card.pagesMax": "최대 페이지", - "pricing.card.aiTranslation": "AI 번역", - "pricing.card.unlimited": "무제한", - "pricing.card.perMonthStat": "/ 월", - "pricing.card.perDoc": "p / 문서", - "pricing.card.aiEssential": "에센셜", - "pricing.card.aiEssentialPremium": "에센셜 + 프리미엄", - "pricing.card.aiCustom": "맞춤", - "pricing.card.myPlan": "내 플랜", - "pricing.card.managePlan": "플랜 관리", - "pricing.card.startFree": "무료로 시작", - "pricing.card.contactUs": "문의하기", - "pricing.card.choosePlan": "이 플랜 선택", - "pricing.card.processing": "처리 중…", - "pricing.comparison.title": "상세 비교", - "pricing.comparison.subtitle": "각 플랜에 포함된 모든 기능", - "pricing.comparison.feature": "기능", - "pricing.comparison.docsPerMonth": "문서 / 월", - "pricing.comparison.pagesMaxPerDoc": "최대 페이지 / 문서", - "pricing.comparison.maxFileSize": "최대 파일 크기", - "pricing.comparison.googleTranslation": "Google 번역", - "pricing.comparison.deepl": "DeepL", - "pricing.comparison.aiEssential": "에센셜 AI 번역", - "pricing.comparison.aiPremium": "프리미엄 AI 번역", - "pricing.comparison.apiAccess": "API 액세스", - "pricing.comparison.priorityProcessing": "우선 처리", - "pricing.comparison.support": "지원", - "pricing.comparison.support.community": "커뮤니티", - "pricing.comparison.support.email": "이메일", - "pricing.comparison.support.priority": "우선", - "pricing.comparison.support.dedicated": "전담", - "pricing.comparison.mb": "MB", - "pricing.credits.title": "추가 크레딧", - "pricing.credits.subtitle": "더 필요하세요? 구독 없이 크레딧을 개별 구매하세요.", - "pricing.credits.perPage": "1 크레딧 = 1번역 페이지.", - "pricing.credits.bestValue": "최고 가성비", - "pricing.credits.unit": "크레딧", - "pricing.credits.centsPerCredit": "센트 / 크레딧", - "pricing.credits.buy": "구매", - "pricing.trust.encryption.title": "종단간 암호화", - "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 (저장 시)", - "pricing.trust.languages.title": "130+개 언어", - "pricing.trust.languages.sub": "아랍어, 페르시아어, 히브리어 (RTL) 포함", - "pricing.trust.parallel.title": "병렬 처리", - "pricing.trust.parallel.sub": "초고속 멀티스레드 AI", - "pricing.trust.availability.title": "24/7 이용 가능", - "pricing.trust.availability.sub": "99.9% 가동 보장", - "pricing.aiModels.title": "AI 모델 — 2026년 3월", - "pricing.aiModels.essential.title": "에센셜 AI 번역", - "pricing.aiModels.essential.plan": "Pro 플랜", - "pricing.aiModels.essential.descPrefix": "기반:", - "pricing.aiModels.essential.descSuffix": "— 2026년 가장 비용 효율적인 AI 모델. 프론티어 모델과 동등한 품질을 극소수의 비용으로 제공.", - "pricing.aiModels.essential.modelName": "Essential AI 모델", - "pricing.aiModels.essential.context": "163K 토큰 컨텍스트", - "pricing.aiModels.essential.value": "우수한 가성비", - "pricing.aiModels.premium.title": "프리미엄 AI 번역", - "pricing.aiModels.premium.plan": "Business 플랜", - "pricing.aiModels.premium.descPrefix": "기반:", - "pricing.aiModels.premium.descSuffix": "Anthropic사 제품 — 법률, 의료 및 복잡한 기술 문서에서 높은 정확도.", - "pricing.aiModels.premium.context": "200K 토큰 컨텍스트", - "pricing.aiModels.premium.precision": "최고 정확도", - "pricing.faq.title": "자주 묻는 질문", - "pricing.faq.q1": "언제든지 플랜을 변경할 수 있나요?", - "pricing.faq.a1": "네. 업그레이드는 즉시 적용되며 일할 계산됩니다. 다운그레이드는 현재 기간 종료 시 적용됩니다.", - "pricing.faq.q2": "「에센셜 AI 번역」이란 무엇인가요?", - "pricing.faq.a2": "당사의 AI 엔진입니다. 문서의 맥락을 이해하고, 레이아웃을 보존하며, 기술 용어를 기존 번역보다 훨씬 잘 처리합니다.", - "pricing.faq.q3": "에센셜 AI와 프리미엄 AI의 차이점은 무엇인가요?", - "pricing.faq.a3": "Essential AI는 최적화된 모델을 사용합니다 (우수한 가성비). Premium AI는 Anthropic의 Claude 3.5 Haiku를 사용하여 법률, 의료 및 복잡한 기술 문서에서 더 정확합니다.", - "pricing.faq.q4": "번역 후 문서가 보관되나요?", - "pricing.faq.a4": "번역된 파일은 플랜에 따라 이용 가능합니다 (Starter 30일, Pro 90일, Business 1년). 저장 시 및 전송 중 암호화됩니다.", - "pricing.faq.q5": "월간 할당량을 초과하면 어떻게 되나요?", - "pricing.faq.a5": "추가 크레딧을 개별 구매하거나 플랜을 업그레이드할 수 있습니다. 사용량이 80%에 도달하면 알림을 받습니다.", - "pricing.faq.q6": "유료 플랜의 무료 체험이 있나요?", - "pricing.faq.a6": "무료 플랜은 영구적이며 신용카드가 필요 없습니다. Pro 및 Business 플랜의 경우 14일 체험을 위해 문의해 주세요.", - "pricing.faq.q7": "어떤 파일 형식을 지원하나요?", - "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx), 그리고 곧 PDF. 모든 플랜에서 동일한 형식을 지원합니다.", - "pricing.cta.title": "시작할 준비가 되셨나요?", - "pricing.cta.subtitle": "신용카드 없이 무료로 시작하세요. 필요할 때 업그레이드하세요.", - "pricing.cta.createAccount": "무료 계정 만들기", - "pricing.cta.login": "로그인", - "pricing.toast.demo": "데모 모드 — Stripe가 아직 구성되지 않았습니다. 프로덕션에서는 결제 페이지로 리디렉션되어 {planId} 플랜을 활성화합니다.", - "pricing.toast.networkError": "네트워크 오류. 다시 시도해 주세요.", - "pricing.toast.paymentError": "결제 생성 중 오류가 발생했습니다.", - "register.title": "계정 만들기", - "register.subtitle": "무료로 번역 시작", - "register.error.failed": "가입 실패", - "register.name.label": "이름", - "register.name.placeholder": "이름을 입력하세요", - "register.name.error": "이름은 최소 2자 이상이어야 합니다", - "register.email.label": "이메일 주소", - "register.email.placeholder": "you@example.com", - "register.email.error": "유효하지 않은 이메일 주소", - "register.password.label": "비밀번호", - "register.password.error": "비밀번호는 8자 이상이며 대문자, 소문자, 숫자를 각각 하나 이상 포함해야 합니다", - "register.password.show": "비밀번호 표시", - "register.password.hide": "비밀번호 숨기기", - "register.password.strengthLabel": "강도:", - "register.password.strength.weak": "약함", - "register.password.strength.medium": "보통", - "register.password.strength.strong": "강함", - "register.confirmPassword.label": "비밀번호 확인", - "register.confirmPassword.error": "비밀번호가 일치하지 않습니다", - "register.confirmPassword.show": "표시", - "register.confirmPassword.hide": "숨기기", - "register.submit.creating": "계정 생성 중...", - "register.submit.create": "계정 만들기", - "register.hasAccount": "이미 계정이 있으신가요?", - "register.login": "로그인", - "register.terms.prefix": "계정을 만들면 당사의", - "register.terms.link": "서비스 약관에 동의하게 됩니다", - "login.signInToContinue": "Sign in to continue translating", - "login.email": "Email", - "login.emailPlaceholder": "you@example.com", - "login.password": "Password", - "login.forgotPassword": "Forgot password?", - "login.passwordPlaceholder": "••••••••", - "login.signingIn": "Signing in...", - "login.signIn": "Sign In", - "login.noAccount": "Don't have an account?", - "login.signUpFree": "Sign up for free", - "login.orContinueWith": "또는 이메일로 계속", - "login.google.connecting": "연결 중…", - "login.google.errorGeneric": "Google 로그인 중 문제가 발생했습니다.", - "login.google.errorFailed": "Google 로그인에 실패했습니다. 다시 시도해 주세요.", - "forgotPassword.enterEmail": "Please enter your email address", - "forgotPassword.error": "An error occurred", - "forgotPassword.title": "Forgot Password", - "forgotPassword.checkEmail": "Check your inbox", - "forgotPassword.subtitle": "Enter your email to receive a reset link", - "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", - "forgotPassword.emailLabel": "Email address", - "forgotPassword.emailPlaceholder": "you@example.com", - "forgotPassword.sending": "Sending...", - "forgotPassword.sendLink": "Send reset link", - "forgotPassword.backToLogin": "Back to login", - "forgotPassword.loading": "Loading...", - "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", - "resetPassword.passwordMismatch": "Passwords do not match", - "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", - "resetPassword.error": "An error occurred", - "resetPassword.invalidLink": "Invalid link", - "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", - "resetPassword.requestNewLink": "Request new link", - "resetPassword.successTitle": "Password reset", - "resetPassword.newPasswordTitle": "New password", - "resetPassword.successSubtitle": "You will be redirected to login", - "resetPassword.subtitle": "Set your new password", - "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", - "resetPassword.newPassword": "New password", - "resetPassword.showPassword": "Show password", - "resetPassword.hidePassword": "Hide password", - "resetPassword.confirmPassword": "Confirm password", - "resetPassword.resetting": "Resetting...", - "resetPassword.resetPassword": "Reset password", - "resetPassword.backToLogin": "Back to login", - "resetPassword.loading": "Loading...", - - "common.loading": "로딩 중...", - "profile.header.title": "내 프로필", - "profile.header.subtitle": "계정 및 환경설정을 관리합니다.", - "profile.tabs.account": "계정", - "profile.tabs.subscription": "구독", - "profile.tabs.preferences": "환경설정", - "profile.account.user": "사용자", - "profile.account.memberSince": "가입일", - "profile.plan.label": "플랜", - "profile.plan.free": "Free", - "profile.plan.starter": "Starter", - "profile.plan.pro": "Pro", - "profile.plan.business": "Business", - "profile.plan.enterprise": "Enterprise", - "profile.plan.pricePerMonth": "{price} €/월", - "profile.subscription.canceling": "취소 중", - "profile.subscription.active": "활성", - "profile.subscription.unknown": "알 수 없음", - "profile.subscription.accessUntil": "접근 가능 기한", - "profile.subscription.renewalOn": "갱신일", - "profile.subscription.upgradePlan": "유료 플랜으로 업그레이드", - "profile.subscription.changePlan": "플랜 변경", - "profile.subscription.manageBilling": "결제 관리", - "profile.subscription.billingUnavailable": "결제 포털을 사용할 수 없습니다.", - "profile.subscription.billingError": "결제 포털에 접근하는 중 오류가 발생했습니다.", - "profile.subscription.cancelSuccess": "구독이 취소되었습니다. 기간 종료까지 접근할 수 있습니다.", - "profile.subscription.cancelError": "취소 중 오류가 발생했습니다.", - "profile.subscription.networkError": "네트워크 오류.", - "profile.usage.title": "이번 달 사용량", - "profile.usage.resetOn": "초기화일", - "profile.usage.documents": "문서", - "profile.usage.pages": "페이지", - "profile.usage.extraCredits": "추가 크레딧", - "profile.usage.extraCreditsPlural": "추가 크레딧", - "profile.usage.quotaReached": "할당량 초과", - "profile.usage.quotaReachedDesc": "계속 사용하려면 상위 플랜으로 업그레이드하세요.", - "profile.usage.unlockMore": "유료 플랜으로 더 많은 번역을 사용하세요.", - "profile.usage.viewPlans": "플랜 보기", - "profile.usage.includedInPlan": "플랜에 포함됨", - "profile.danger.title": "위험 구역", - "profile.danger.description": "취소는 현재 기간이 끝나면 적용됩니다. 해당 날짜까지 접근이 유지됩니다.", - "profile.danger.confirm": "정말 진행하시겠습니까? 이 작업은 되돌릴 수 없습니다.", - "profile.danger.confirmCancel": "취소 확인", - "profile.danger.cancelSubscription": "구독 취소", - "profile.danger.keep": "아니요, 유지합니다", - "profile.prefs.interfaceLang": "인터페이스 언어", - "profile.prefs.interfaceLangDesc": "브라우저 설정에 따라 언어가 자동 감지됩니다. 수동으로 변경할 수도 있습니다.", - "profile.prefs.defaultTargetLang": "기본 번역 대상 언어", - "profile.prefs.selectLanguage": "언어 선택", - "profile.prefs.defaultTargetLangDesc": "이 언어가 번역 시 자동으로 선택됩니다.", - "profile.prefs.save": "저장", - "profile.prefs.theme": "테마", - "profile.prefs.themeDesc": "인터페이스 외모를 선택하세요", - "profile.prefs.cache": "캐시", - "profile.prefs.cacheDesc": "로컬 캐시를 지우면 일부 표시 문제가 해결될 수 있습니다.", - "profile.prefs.clearing": "지우는 중...", - "profile.prefs.clearCache": "캐시 지우기", - "settings.title": "설정", - "settings.subtitle": "일반 애플리케이션 설정", - "settings.formats.title": "지원 형식", - "settings.formats.subtitle": "번역 가능한 문서 유형", - "settings.formats.formulas": "수식", - "settings.formats.styles": "스타일", - "settings.formats.images": "이미지", - "settings.formats.headers": "머리글", - "settings.formats.tables": "표", - "settings.formats.slides": "슬라이드", - "settings.formats.notes": "메모", - "settings.cache.title": "캐시", - "settings.cache.desc": "로컬 캐시를 지우면 일부 표시 문제가 해결될 수 있습니다.", - "settings.cache.clearing": "지우는 중...", - "settings.cache.clear": "캐시 지우기", - "services.title": "번역 제공업체", - "services.subtitle": "제공업체는 관리자가 구성합니다. 현재 계정에서 사용 가능한 제공업체를 확인할 수 있습니다.", - "services.loading": "제공업체 로딩 중...", - "services.noProviders": "현재 구성된 제공업체가 없습니다. 관리자에게 문의하세요.", - "services.classic": "클래식 번역", - "services.llmPro": "LLM · 컨텍스트 인식 (Pro)", - "services.available": "사용 가능", - "services.model": "모델", - "services.adminOnly.title": "제공업체 설정은 관리자 전용입니다", - "services.adminOnly.desc": "API 키, 모델 선택, 제공업체 활성화는 관리자가 관리 패널에서 관리합니다. API 키를 입력할 필요가 없습니다.", - "apiKeys.title": "API 키", - "apiKeys.subtitle": "번역 API에 프로그래밍 방식으로 접근하기 위한 API 키를 관리합니다.", - "apiKeys.loading": "로딩 중...", - "apiKeys.sectionTitle": "API & 자동화", - "apiKeys.sectionDesc": "자동화 워크플로우를 위한 API 키 생성 및 관리", - "apiKeys.keysUsed": "{total} / {max} 키 사용", - "apiKeys.maxReached": "최대 키 수에 도달했습니다. 새 키를 생성하려면 기존 키를 취소하세요.", - "apiKeys.canGenerate": "{count}개의 키를 더 생성할 수 있습니다", - "apiKeys.canGeneratePlural": "{count}개의 키를 더 생성할 수 있습니다", - "apiKeys.generateNew": "새 키 생성", - "apiKeys.keyRevoked": "키가 취소되었습니다", - "apiKeys.keyRevokedDesc": "API 키가 성공적으로 취소되었습니다.", - "apiKeys.keyNotFound": "키를 찾을 수 없음", - "apiKeys.keyNotFoundDesc": "API 키가 더 이상 존재하지 않습니다. 이미 취소되었을 수 있습니다.", - "apiKeys.error": "오류", - "apiKeys.revokeError": "API 키 취소에 실패했습니다. 다시 시도해 주세요.", - "apiKeys.limitReached": "한도 도달", - "apiKeys.limitReachedDesc": "API 키는 최대 10개까지입니다. 새 키를 생성하려면 기존 키를 취소하세요.", - "apiKeys.proRequired": "Pro 기능 필요", - "apiKeys.proRequiredDesc": "API 키는 Pro 기능입니다. 계정을 업그레이드해 주세요.", - "apiKeys.generateError": "API 키 생성에 실패했습니다. 다시 시도해 주세요.", - "apiKeys.upgrade.title": "API 키", - "apiKeys.upgrade.subtitle": "API 액세스로 번역 자동화", - "apiKeys.upgrade.feat1": "무제한 API 키 생성", - "apiKeys.upgrade.feat2": "문서 번역 자동화", - "apiKeys.upgrade.feat3": "웹훅 알림", - "apiKeys.upgrade.feat4": "LLM 번역 모드", - "apiKeys.upgrade.proFeature": "API 키는 {pro} 기능입니다. 업그레이드하여 API 자동화를 잠금 해제하세요.", - "apiKeys.upgrade.pro": "Pro", - "apiKeys.upgrade.cta": "Pro로 업그레이드", - "apiKeys.dialog.maxTitle": "최대 키 수 도달", - "apiKeys.dialog.maxDesc": "API 키는 최대 10개까지입니다. 새 키를 생성하기 전에 기존 키를 취소해 주세요.", - "apiKeys.dialog.close": "닫기", - "apiKeys.dialog.generated": "API 키가 생성되었습니다!", - "apiKeys.dialog.generatedDesc": "새 API 키가 생성되었습니다. 지금 복사하세요 - 다시 표시되지 않습니다.", - "apiKeys.dialog.important": "중요:", - "apiKeys.dialog.importantDesc": "이 키가 표시되는 것은 이번뿐입니다. 안전하게 보관하세요.", - "apiKeys.dialog.apiKey": "API 키", - "apiKeys.dialog.name": "이름:", - "apiKeys.dialog.done": "완료", - "apiKeys.dialog.copied": "키를 복사했습니다", - "apiKeys.dialog.generateTitle": "새 API 키 생성", - "apiKeys.dialog.generateDesc": "번역 API에 프로그래밍 방식으로 접근하기 위한 새 API 키를 생성합니다.", - "apiKeys.dialog.keyName": "키 이름 (선택사항)", - "apiKeys.dialog.keyNamePlaceholder": "예: 프로덕션, 스테이징", - "apiKeys.dialog.keyNameHint": "나중에 이 키를 식별할 수 있는 설명적인 이름.", - "apiKeys.dialog.nameTooLong": "이름은 {max}자 이하여야 합니다", - "apiKeys.dialog.nameInvalid": "이름은 문자, 숫자, 공백, 하이픈, 밑줄만 포함할 수 있습니다", - "apiKeys.dialog.cancel": "취소", - "apiKeys.dialog.generating": "생성 중...", - "apiKeys.dialog.generate": "키 생성", - "apiKeys.table.name": "이름", - "apiKeys.table.prefix": "접두사", - "apiKeys.table.created": "생성일", - "apiKeys.table.lastUsed": "마지막 사용", - "apiKeys.table.never": "사용 안 함", - "apiKeys.table.actions": "작업", - "apiKeys.table.revoke": "취소", - "apiKeys.table.copyPrefix": "키 접두사 복사", - "apiKeys.table.revokeKey": "키 취소", - "apiKeys.revokeDialog.title": "API 키 취소", - "apiKeys.revokeDialog.desc": "키 \"{name}\"을(를) 취소하시겠습니까? 이 작업은 되돌릴 수 없습니다.", - "apiKeys.revokeDialog.confirm": "예, 취소합니다", - "apiKeys.revokeDialog.cancel": "취소", - "context.proTitle": "Pro 기능", - "context.proDesc": "컨텍스트 및 전문 용어집은 Pro, Business, Enterprise 플랜에서 사용할 수 있습니다. 도메인별 지침과 어휘를 통해 더 정확한 번역을 제공합니다.", - "context.viewPlans": "플랜 보기", - "context.title": "컨텍스트 & 용어집", - "context.subtitle": "도메인별 지침과 어휘로 번역 품질을 향상시킵니다.", - "context.presets.title": "전문 용어집", - "context.presets.desc": "지침과 전문 용어가 포함된 완전한 용어집을 불러옵니다", - "context.instructions.title": "컨텍스트 지침", - "context.instructions.desc": "번역 중 AI가 따를 지침", - "context.instructions.placeholder": "예: HVAC 기술 문서를 번역합니다. 정확한 공학 용어를 사용하세요...", - "context.glossary.title": "기술 용어집", - "context.glossary.desc": "형식: source=target (한 줄에 하나). 프리셋으로 불러온 용어집은 편집 가능합니다.", - "context.glossary.terms": "용어집의 용어 수", - "context.clearAll": "모두 지우기", - "context.saving": "저장 중...", - "context.save": "저장", - "translate.glossary.title": "용어집", - "translate.glossary.select": "용어집 선택", - "translate.glossary.none": "없음", - "translate.glossary.terms": "개", - "translate.glossary.proOnly": "Pro로 업그레이드하여 용어집 사용", - "translate.glossary.myGlossaries": "내 용어집", - "translate.glossary.fromTemplate": "템플릿에서 만들기", - "translate.glossary.noGlossaryForPair": "용어집 없음", - "translate.glossary.noGlossaries": "용어집 없음", - "translate.glossary.loading": "로딩 중...", - "translate.glossary.classicMode": "용어집 없는 중립 엔진 (AI만)", - "translate.glossary.selectPlaceholder": "용어집 선택...", - "translate.glossary.multilingual": "다국어", - "translate.glossary.noGlossaryAvailable": "사용 가능한 용어집 없음", - "translate.glossary.filterByLang": "언어별 필터", - "translate.glossary.active": "활성", - "translate.glossary.inactive": "비활성", - "translate.glossary.availableTemplates": "사용 가능한 템플릿", - "translate.glossary.importing": "가져오는 중...", - "translate.glossary.imported": "(가져옴)", - "translate.glossary.noGlossaryForSource": "원본 언어에 대한 용어집 또는 템플릿 없음", - "translate.glossary.createGlossary": "용어집 만들기", - "translate.glossary.showAll": "모든 용어집 표시", - "translate.glossary.activePreview": "활성 일치 미리보기:", - "translate.glossary.total": "총", - "translate.glossary.moreTerms": "추가 용어", - "translate.glossary.noTerms": "이 용어집에 용어가 없습니다.", - "translate.glossary.sourceTerm": "원본 용어", - "translate.glossary.translation": "번역", - "translate.glossary.addTerm": "용어 추가", - "translate.glossary.disabledMode": "용어집이 적용되지 않은 중립 엔진", - "translate.glossary.addTermError": "용어 추가 오류", - "translate.glossary.networkError": "네트워크 오류", - "translate.glossary.importFailed": "가져오기 실패 ({status})", - "translate.glossary.helpText": "용어집은 정확한 용어 번역을 강제합니다. 원본 언어가 문서의 원래 언어와 일치하는 용어집을 선택하세요.", - "translate.glossary.sourceWarning": "주의: 이 용어집은 원본 언어를 사용합니다", - "translate.glossary.sourceWarningBut": "하지만 문서가 다음으로 설정되어 있습니다", - "translate.glossary.targetWarning": "대상 불일치: 이 용어집은 다음 언어로 번역하도록 설계되었습니다", - "translate.glossary.targetWarningBut": "하지만 문서의 대상은", - "translate.glossary.targetWarningEnd": "용어가 관련이 없을 수 있습니다.", - "context.presets.createGlossary": "용어집 만들기", - "context.presets.created": "용어집 생성됨", - "context.presets.createdDesc": "용어집 \"{name}\"이(가) {count}개의 용어로 생성되었습니다.", - "context.presets.hint": "프리셋을 클릭하여 도메인별 용어가 포함된 용어집을 만드세요. 용어집 섹션에서 관리할 수 있습니다.", - "context.glossary.manage": "용어집 관리", - "context.saved": "저장됨", - "context.savedDesc": "컨텍스트 지침이 저장되었습니다.", - "admin.login.title": "관리", - "admin.login.required": "로그인 필요", - "admin.login.password": "관리자 비밀번호", - "admin.login.connecting": "연결 중...", - "admin.login.access": "관리 패널 접속", - "admin.login.restricted": "관리자 전용", - "admin.layout.checking": "인증 확인 중...", - "admin.dashboard.title": "관리 대시보드", - "admin.dashboard.subtitle": "관리자 제어판", - "admin.dashboard.refresh": "새로고침", - "admin.dashboard.refreshTooltip": "대시보드 데이터 새로고침", - "admin.dashboard.config": "시스템 구성", - "admin.dashboard.maxFileSize": "최대 파일 크기:", - "admin.dashboard.translationService": "번역 서비스:", - "admin.dashboard.formats": "형식:", - "admin.nav.dashboard": "Dashboard", - "admin.nav.users": "사용자", - "admin.nav.pricing": "요금 & Stripe", - "admin.nav.providers": "제공업체", - "admin.nav.system": "시스템", - "admin.nav.logs": "로그", - "admin.users.title": "사용자 관리", - "admin.users.subtitle": "사용자 계정 보기 및 관리", - "admin.users.planUpdated": "플랜이 업데이트되었습니다", - "admin.users.planChanged": "플랜이 \"{plan}\"(으)로 성공적으로 변경되었습니다.", - "admin.users.unknownError": "알 수 없는 오류", - "admin.users.error": "오류", - "admin.users.planUpdateError": "플랜을 업데이트할 수 없습니다: {message}", - "admin.users.noKeys": "키 없음", - "admin.users.noKeysDesc": "이 사용자는 활성 API 키가 없습니다.", - "admin.users.keysRevoked": "키가 취소되었습니다", - "admin.users.keysRevokedDesc": "{count}개의 API 키가 성공적으로 취소되었습니다.", - "admin.users.revokeError": "키를 취소할 수 없습니다: {message}", - "admin.users.retry": "재시도", - "admin.system.title": "시스템", - "admin.system.subtitle": "시스템 상태 모니터링 및 리소스 관리", - "admin.system.quotas": "번역 할당량", - "admin.system.resetQuotas": "월간 할당량 초기화", - "admin.system.resetting": "초기화 중...", - "admin.system.reset": "초기화", - "admin.system.allOperational": "모든 시스템 정상 가동 중", - "admin.system.issuesDetected": "시스템 문제가 감지되었습니다", - "admin.system.waitingData": "데이터 대기 중...", - "admin.system.purging": "삭제 중...", - "admin.system.clean": "정리", - "admin.system.purge": "삭제", - "memento.title": "Momento 발견하기", - "memento.slogan": "Momento는 단순한 메모 앱이 아닙니다. 6개의 AI 에이전트와 최첨단 시맨틱 검색을 사용하여 아이디어를 실시간으로 연결, 분석, 발전시키는 지능형 생태계입니다.", - "memento.ctaFree": "무료로 시작", - "memento.ctaMore": "자세히 보기", - "common.backToHome": "홈으로 돌아가기", - "dashboard.topbar.interfaceLabel": "번역 인터페이스", - "dashboard.topbar.premiumAccess": "프리미엄 액세스", - "landing.hero.contextEngine": "번역 감지됨: HVAC 시스템 기술 유지보수 용어...", - "landing.hero.liveAnalysis": "실시간 분석", - "landing.hero.termsDetected": "개 용어 감지됨", - "landing.steps.process": "프로세스", - "landing.translate.newProject": "새 프로젝트", - "landing.translate.title": "문서 번역", - "landing.translate.subtitle": "파일을 가져오고 대상 언어를 선택하세요", - "landing.translate.sourceDocument": "원본 문서", - "landing.translate.configuration": "설정", - "landing.translate.sourceLang": "원본 언어", - "landing.translate.targetLang": "대상 언어", - "landing.translate.provider": "제공자", - "landing.translate.startTranslation": "번역 시작", - "landing.translate.zeroRetention": "제로 보관", - "landing.translate.filesDeleted": "처리 후 파일 삭제됨", - "landing.translate.dropHere": "여기에 드래그 앤 드롭", - "landing.translate.supportedFormats": "DOCX, XLSX, PPTX 또는 PDF 파일 지원", - "landing.translate.aiAnalysis": "AI 분석 활성", - "landing.translate.processing": "처리 중", - "landing.translate.preservingLayout": "레이아웃이 보존되고 있습니다", - "layout.nav.apiAccess": "API 액세스", - "layout.footer.terms": "약관", - "layout.footer.privacy": "개인정보", - "fileUploader.uploadDocument": "문서 업로드", - "fileUploader.uploadDesc": "파일을 끌어다 놓거나 클릭하여 선택 (Excel, Word, PowerPoint)", - "fileUploader.dropHere": "파일을 여기에 놓으세요…", - "fileUploader.dragAndDrop": "여기에 문서를 끌어다 놓으세요", - "fileUploader.orClickBrowse": "또는 클릭하여 찾아보기", - "fileUploader.preview": "미리보기", - "fileUploader.translationOptions": "번역 옵션", - "fileUploader.configureSettings": "번역 설정 구성", - "fileUploader.targetLanguage": "대상 언어", - "fileUploader.selectLanguage": "언어 선택", - "fileUploader.translationProvider": "번역 공급자", - "fileUploader.selectProvider": "공급자 선택", - "fileUploader.advancedOptions": "고급 옵션", - "fileUploader.translateImages": "이미지 번역", - "fileUploader.translating": "번역 중…", - "fileUploader.translateDocument": "문서 번역", - "fileUploader.processing": "처리 중…", - "fileUploader.translationError": "번역 오류", - "fileUploader.translationComplete": "번역 완료!", - "fileUploader.translationCompleteDesc": "서식을 모두 유지한 채 문서가 성공적으로 번역되었습니다.", - "fileUploader.download": "번역된 문서 다운로드", - "fileUploader.webgpuUnsupported": "이 브라우저는 WebGPU를 지원하지 않습니다. Chrome 113+ 또는 Edge 113+를 사용하세요.", - "fileUploader.webllmNotLoaded": "WebLLM 모델이 로드되지 않았습니다. 설정 > 번역 서비스에서 모델을 먼저 로드하세요.", - "fileUploader.extracting": "문서에서 텍스트 추출 중…", - "fileUploader.noTranslatable": "문서에서 번역 가능한 텍스트를 찾을 수 없음", - "fileUploader.foundTexts": "번역할 텍스트 {count}개 발견", - "fileUploader.translatingItem": "번역 중 {current}/{total}: \"{preview}\"", - "fileUploader.reconstructing": "문서 재구성 중…", - "fileUploader.translatingLocally": "WebLLM으로 로컬 번역 중…", - "checkout.activating": "활성화 중…", - "checkout.activatingDesc": "구독을 업데이트 중입니다. 잠시 기다려 주세요.", - "checkout.paymentConfirmed": "결제 확인됨!", - "checkout.subscriptionActivated": "구독이 활성화되었습니다!", - "checkout.planActivated": "{plan} 요금제가 활성화되었습니다!", - "checkout.redirectingToProfile": "프로필로 리디렉션 중…", - "checkout.paymentReceived": "결제 받음", - "checkout.redirecting": "리디렉션 중…", - "checkout.syncError": "동기화 오류", - "checkout.networkError": "네트워크 오류. 결제가 확인되었습니다 — 프로필을 새로 고치세요.", - "dashboard.checkoutSyncError": "결제 동기화 오류.", - "dashboard.networkRefresh": "네트워크 오류. 페이지를 새로 고치세요.", - "dashboard.continueToTranslate": "번역으로 계속", - "langSelector.search": "검색…", - "langSelector.noResults": "결과 없음", - "langSelector.source": "원본", - "langSelector.target": "대상", - "langSelector.swap": "교환", - "translateComplete.highQuality": "고품질", - "translateComplete.segments": "세그먼트", - "translateComplete.characters": "문자", - "translateComplete.confidence": "신뢰도", - "providerTheme.deepseek.badge": "필수", - "providerTheme.deepseek.subBadge": "기술 및 경제", - "providerTheme.deepseek.desc": "초정밀 경제적 번역. 기술 문서 및 코드에 이상적.", - "providerTheme.openai.badge": "프리미엄", - "providerTheme.openai.subBadge": "고충실도", - "providerTheme.openai.desc": "세계적 AI 표준. 최대 텍스트 일관성과 엄격한 스타일 준수.", - "providerTheme.minimax.badge": "고급", - "providerTheme.minimax.subBadge": "성능", - "providerTheme.minimax.desc": "놀라운 실행 속도와 복잡한 구조에 대한 뛰어난 이해.", - "providerTheme.openrouter.badge": "익스프레스", - "providerTheme.openrouter.subBadge": "멀티 모델", - "providerTheme.openrouter.desc": "번역에 최적화된 최고의 오픈소스 모델에 대한 통합 액세스.", - "providerTheme.openrouter_premium.badge": "울트라", - "providerTheme.openrouter_premium.subBadge": "최대 컨텍스트", - "providerTheme.openrouter_premium.desc": "최신 모델(GPT-4o, Claude Sonnet 4.6)의 지원을 받는 긴 문서 번역.", - "providerTheme.zai.badge": "전문", - "providerTheme.zai.subBadge": "금융 및 법률", - "providerTheme.zai.desc": "까다로운 비즈니스 용어(법률, 금융)에 맞게 미세 조정된 모델.", - "providerTheme.default.badge": "모던", - "providerTheme.default.subBadge": "AI 추론", - "providerTheme.default.desc": "대규모 언어 모델(LLM) 번역, 고급 의미 분석 포함.", - "providerTheme.classic.google.label": "Google 번역", - "providerTheme.classic.google.desc": "130개 이상의 언어를 지원하는 초고속 번역. 일반적인 워크플로에 권장.", - "providerTheme.classic.deepl.label": "DeepL Pro", - "providerTheme.classic.deepl.desc": "유창함과 자연스러운 표현으로 유명한 고정밀 번역.", - "providerTheme.classic.google_cloud.label": "Google Cloud API", - "providerTheme.classic.google_cloud.desc": "대용량 문서 처리에 최적화된 전문 클라우드 엔진.", - "providerSelector.noClassic": "사용 가능한 표준 번역기가 없습니다.", - "providerSelector.noLlm": "구성된 AI 모델이 없습니다.", - "providerSelector.costOne": "비용: 페이지당 1 크레딧", - "providerSelector.costFive": "비용: 페이지당 5 크레딧 (프리미엄 요율)", - "providerSelector.unlockContextual": "전체 문서를 위한 프리미엄 컨텍스트 번역 잠금 해제.", - "translate.header.processing": "처리 진행 중", - "translate.header.aiActive": "AI 분석 활성", - "translate.header.aiActiveDesc": "레이아웃이 컨텍스트 엔진에 의해 보존되고 있습니다.", - "translate.header.completed": "완료됨", - "translate.header.completedTitle": "번역 완료", - "translate.header.proSpace": "Pro 공간", - "translate.header.translateDoc": "문서 번역", - "translate.header.translateDocDesc": "초고충실도 번역 엔진으로 원본 레이아웃을 유지하세요.", - "translate.upload.nativeFormat": "네이티브 형식", - "translate.fileType.word": "Word (.docx)", - "translate.fileType.excel": "Excel (.xlsx)", - "translate.fileType.slides": "슬라이드 (.pptx)", - "translate.fileType.pdf": "PDF (.pdf)", - "translate.startTranslation": "번역 시작", - "translate.submit": "제출 중…", - "translate.chooseTargetLang": "대상 언어를 선택하세요", - "translate.pleaseLoadFile": "먼저 파일을 업로드하세요", - "translate.contextEngineActive": "컨텍스트 엔진 활성", - "translate.phase1": "1단계: 초기화", - "translate.phase2": "2단계: 컨텍스트 재구성", - "translate.stat.segments": "세그먼트", - "translate.stat.precision": "정밀도", - "translate.stat.speedLabel": "속도", - "translate.stat.turbo": "터보", - "translate.stat.time": "시간", - "translate.complete.masterQuality": "✓ 마스터 품질", - "translate.download": "다운로드", - "translate.newTranslation": "+ 새 번역", - "translate.failedTitle": "번역 오류", - "translate.retry": "재시도", - "translate.uploadAnother": "다른 파일 업로드", - "translate.monitor": "AI 모니터", - "translate.summary": "요약", - "translate.cancelProcess": "⟳ 프로세스 취소", - "translate.layoutIntegrity": "레이아웃 무결성", - "translate.secureHundred": "100% 안전", - "translate.okHundred": "100% OK", - "translate.preserveLayout": "레이아웃 유지", - "translate.preserveLayoutDesc": "레이아웃 유지", - "translate.textOnly": "텍스트만", - "translate.textOnlyDesc": "텍스트만 빠른 번역", - "translate.unavailableStandard": "표준 모드에서 사용 불가 (AI만)", - "apiKeys.noKeysGenerated": "생성된 키 없음", - "apiKeys.copied": "복사됨!", - "services.fallback.google.label": "Google 번역", - "services.fallback.google.desc": "빠른 번역, 130개 이상의 언어", - "settings.formats.excel.name": "Excel", - "settings.formats.word.name": "Word", - "settings.formats.powerpoint.name": "PowerPoint", - "pricing.dashboard": "대시보드", - "pricing.okSymbol": "✓", - "pricing.errSymbol": "✕", - }, - // ═══════════════════════════════════════════════════════════════ - // CHINESE SIMPLIFIED (zh) - // ═══════════════════════════════════════════════════════════════ - zh: { - "auth.brandName": "Wordly", - "dashboard.nav.translate": "翻译", - "dashboard.nav.profile": "我的资料", - "dashboard.nav.settings": "设置", - "dashboard.nav.context": "上下文", - "dashboard.nav.services": "服务", - "dashboard.nav.apiKeys": "API 密钥", - "dashboard.nav.glossaries": "术语表", - "dashboard.header.title": "控制面板", - "dashboard.header.subtitle": "管理您的翻译", - "dashboard.header.toggleMenu": "菜单", - "dashboard.header.profileTitle": "我的资料", - "dashboard.sidebar.theme": "主题", - "dashboard.sidebar.signOut": "退出登录", - "dashboard.sidebar.backHome": "返回首页", - "dashboard.sidebar.upgradeToPro": "升级到 Pro →", - "cookieConsent.title": "Wordly 的 Cookie", - "cookieConsent.description": "我们使用必要的 Cookie 以确保应用正常运行(会话、安全、语言)。在您的许可下,我们还会使用可选 Cookie 来衡量流量和改进产品。", - "cookieConsent.acceptAll": "全部接受", - "cookieConsent.essentialOnly": "仅限必要", - "cookieConsent.learnMore": "了解更多", - "login.orContinueWith": "或使用电子邮件继续", - "login.google.connecting": "连接中…", - "login.google.errorGeneric": "Google 登录时出现问题。", - "login.google.errorFailed": "Google 登录失败。请重试。", - "landing.nav.why": "为什么选择我们", - "landing.nav.formats": "支持格式", - "landing.nav.pricing": "定价", - "landing.nav.login": "登录", - "landing.nav.startFree": "免费开始", - "landing.hero.tag": "专业文档AI", - "landing.hero.titleLine1": "翻译您的文档。", - "landing.hero.titleLine2": "完美保留格式。", - "landing.hero.description": "唯一能够保留SmartArt、图表、目录、形状和复杂布局的翻译工具——与原始格式完全一致。", - "landing.hero.ctaMain": "免费开始 — 每月2份文档", - "landing.hero.ctaSec": "查看方案", - "landing.hero.deleted": "文件60分钟后删除", - "landing.hero.noHidden": "无隐藏费用", - "landing.hero.preview": "付款前预览", - "landing.hero.formattedOk": "格式正常", - "landing.hero.aiActive": "AI翻译已启用", - "landing.steps.title": "如何使用?", - "landing.steps.subtitle": "三个步骤,零格式损失。", - "landing.steps.step1.num": "01", - "landing.steps.step1.title": "上传文件", - "landing.steps.step1.desc": "拖放您的Excel、Word、PowerPoint或PDF文档。", - "landing.steps.step2.num": "02", - "landing.steps.step2.title": "选择语言和引擎", - "landing.steps.step2.desc": "选择目标语言和翻译引擎——经典引擎或上下文感知AI。", - "landing.steps.step3.num": "03", - "landing.steps.step3.title": "下载结果", - "landing.steps.step3.desc": "获取与原始格式完全一致的翻译文档。", - "landing.features.tag": "AI翻译引擎", - "landing.features.title": "理解您专业的翻译", - "landing.features.description": "我们的AI模型分析上下文、尊重您的术语,甚至翻译图片中的文字。", - "landing.features.context.title": "行业上下文", - "landing.features.context.desc": "描述您的行业,获得定制化翻译,而非通用翻译。", - "landing.features.glossary.title": "行业术语表", - "landing.features.glossary.desc": "定义您的专业术语。CTA保持为「空气处理机组」,而非「行动号召」。", - "landing.features.vision.title": "图像识别", - "landing.features.vision.desc": "嵌入在图片、图表和图形中的文字会被检测并翻译。", - "landing.features.demo.source": "原文(FR)", - "landing.features.demo.google": "Google翻译", - "landing.features.demo.ours": "我们的AI", - "landing.layout.title": "您的格式,", - "landing.layout.title2": "完美保留", - "landing.layout.subtitle": "其他翻译工具会破坏您的排版。我们不会。", - "landing.layout.p1.title": "SmartArt和图表", - "landing.layout.p1.desc": "组织结构图、流程图、层级图——全部精确翻译。", - "landing.layout.p2.title": "目录", - "landing.layout.p2.desc": "目录条目、页码和交叉引用正确更新。", - "landing.layout.p3.title": "图表和图形", - "landing.layout.p3.desc": "标题、轴标签、图例和系列名称——全部翻译。", - "landing.layout.p4.title": "形状和文本框", - "landing.layout.p4.desc": "矩形、圆角块、标注——全面本地化。", - "landing.layout.p5.title": "页眉和页脚", - "landing.layout.p5.desc": "页眉、页脚和脚注绝不会被遗漏。", - "landing.layout.p6.title": "130+种语言", - "landing.layout.p6.desc": "Google翻译、DeepL及专业级AI引擎。", - "landing.formats.title": "每种格式,", - "landing.formats.title2": "每个元素", - "landing.formats.subtitle": "我们翻译其他工具遗漏的内容。您的企业值得拥有完美无瑕的文档。", - "landing.formats.word.name": "Word", - "landing.formats.word.i1": "段落和标题", - "landing.formats.word.i2": "表格和图表", - "landing.formats.word.i3": "SmartArt图表", - "landing.formats.word.i4": "目录", - "landing.formats.word.i5": "页眉和页脚", - "landing.formats.word.i6": "形状和文本框", - "landing.formats.word.i7": "脚注和尾注", - "landing.formats.excel.name": "Excel", - "landing.formats.excel.i1": "单元格值", - "landing.formats.excel.i2": "工作表名称", - "landing.formats.excel.i3": "图表和标签", - "landing.formats.excel.i4": "页眉和页脚", - "landing.formats.excel.i5": "合并单元格保留", - "landing.formats.pptx.name": "PowerPoint", - "landing.formats.pptx.i1": "幻灯片文本和备注", - "landing.formats.pptx.i2": "图表和图形", - "landing.formats.pptx.i3": "形状和文本框", - "landing.formats.pptx.i4": "母版布局", - "landing.formats.pptx.i5": "动画保留", - "landing.formats.pdf.name": "PDF", - "landing.formats.pdf.i1": "基于文本的PDF", - "landing.formats.pdf.i2": "布局保留", - "landing.formats.pdf.i3": "图片保持在原位", - "landing.formats.pdf.i4": "表格保持", - "landing.formats.pdf.i5": "输出为DOCX或PDF", - "landing.pricing.title": "简单透明的定价", - "landing.pricing.subtitle": "所见即所付。无隐藏费用。", - "landing.pricing.monthly": "月付", - "landing.pricing.annual": "年付", - "landing.pricing.bestValue": "最受欢迎", - "landing.pricing.month": "/月", - "landing.pricing.footer": "显示的价格就是您支付的价格。翻译后无任何隐藏费用。", - "landing.pricing.starter.name": "Starter", - "landing.pricing.starter.desc": "适合个人和小型项目", - "landing.pricing.starter.f1": "每月50份文档", - "landing.pricing.starter.f2": "每份文档最多50页", - "landing.pricing.starter.f3": "Google翻译 + DeepL", - "landing.pricing.starter.f4": "文件最大10 MB", - "landing.pricing.starter.cta": "立即开始", - "landing.pricing.pro.name": "Pro", - "landing.pricing.pro.desc": "适合专业用户", - "landing.pricing.pro.f1": "每月200份文档", - "landing.pricing.pro.f2": "每份文档最多200页", - "landing.pricing.pro.f3": "AI翻译", - "landing.pricing.pro.f4": "包含Google + DeepL", - "landing.pricing.pro.f5": "自定义术语表和提示词", - "landing.pricing.pro.f6": "优先支持", - "landing.pricing.pro.cta": "试用Pro", - "landing.pricing.business.name": "企业版", - "landing.pricing.business.desc": "适合大批量需求的团队", - "landing.pricing.business.f1": "每月1,000份文档", - "landing.pricing.business.f2": "每份文档最多500页", - "landing.pricing.business.f3": "高级AI(Claude)", - "landing.pricing.business.f4": "所有供应商 + API", - "landing.pricing.business.f5": "Webhook和自动化", - "landing.pricing.business.f6": "5个团队席位", - "landing.pricing.business.cta": "联系我们", - "landing.cta.title": "30秒开始翻译", - "landing.cta.subtitle": "无需信用卡。立即免费试用,让您的多语言文档重获新生。", - "landing.cta.button": "创建免费账户", - "landing.cta.secure": "AES-256加密保护", - "landing.footer.desc": "智能文档翻译专家。我们将排版的艺术与上下文AI的科学完美融合。", - "landing.footer.product": "产品", - "landing.footer.resources": "资源", - "landing.footer.legal": "法律", - "landing.footer.rights": "© 2026 Wordly.art — 保留所有权利。", - "dashboard.translate.pageTitle": "翻译文档", - "dashboard.translate.pageSubtitle": "导入文件并选择目标语言", - "dashboard.translate.errorNotificationTitle": "错误", - "dashboard.translate.dropzone.uploadAria": "文件拖放区", - "dashboard.translate.dropzone.title": "将文件拖放到此处", - "dashboard.translate.dropzone.subtitle": "或点击选择(DOCX、XLSX、PPTX、PDF)", - "dashboard.translate.dropzone.replaceFile": "替换文件", - "dashboard.translate.language.source": "源语言", - "dashboard.translate.language.target": "目标语言", - "dashboard.translate.language.loading": "正在加载语言…", - "dashboard.translate.language.autoDetect": "自动检测", - "dashboard.translate.language.selectPlaceholder": "选择…", - "dashboard.translate.language.loadErrorPrefix": "语言加载失败", - "dashboard.translate.provider.loading": "正在加载服务商…", - "dashboard.translate.provider.noneConfigured": "未配置服务商", - "dashboard.translate.provider.modelTitle": "模型", - "dashboard.translate.provider.sectionTitle": "服务商", - "dashboard.translate.provider.llmDivider": "AI · 上下文感知", - "dashboard.translate.provider.llmDividerPro": "AI · 上下文感知(专业版)", - "dashboard.translate.provider.upgrade": "升级到专业版", - "dashboard.translate.provider.upgradeSuffix": "以解锁 AI 翻译", - "dashboard.translate.trust.zeroRetention": "零数据留存", - "dashboard.translate.trust.deletedAfter": "处理完成后文件即被删除", - "dashboard.translate.actions.uploading": "正在上传…", - "dashboard.translate.actions.translate": "翻译", - "dashboard.translate.actions.filePrefix": "文件:", - "dashboard.translate.actions.cancel": "取消", - "dashboard.translate.actions.tryAgain": "重试", - "dashboard.translate.steps.uploading": "正在上传文件…", - "dashboard.translate.steps.starting": "正在开始翻译…", - "dashboard.translate.complete.title": "翻译完成!", - "dashboard.translate.complete.descNamed": "您的文件 {name} 已成功翻译。", - "dashboard.translate.complete.descGeneric": "您的文件已成功翻译。", - "dashboard.translate.complete.downloading": "正在下载…", - "dashboard.translate.complete.download": "下载", - "dashboard.translate.complete.newTranslation": "新建翻译", - "dashboard.translate.complete.toastOkTitle": "成功", - "dashboard.translate.complete.toastOkDesc": "{name} 已成功下载。", - "dashboard.translate.complete.toastFailTitle": "失败", - "dashboard.translate.complete.toastFailDesc": "翻译失败,请重试。", - "dashboard.translate.sourceDocument": "源文档", - "dashboard.translate.configuration": "配置", - "dashboard.translate.translating": "翻译进行中", - "dashboard.translate.liveMonitor": "实时监控", - "dashboard.translate.summary": "摘要", - "dashboard.translate.engine": "引擎", - "dashboard.translate.confidence": "置信度", - "dashboard.translate.cancel": "取消", - "dashboard.translate.segments": "片段", - "dashboard.translate.characters": "字符", - "dashboard.translate.elapsed": "已用时间", - "dashboard.translate.segPerMin": "片段/分钟", - "dashboard.translate.highQuality": "高质量", - "dashboard.translate.quality": "质量", - "dashboard.translate.completed": "翻译完成", - "dashboard.translate.replace": "替换", - "dashboard.translate.pdfMode.title": "PDF翻译模式", - "dashboard.translate.pdfMode.preserveLayout": "保留排版", - "dashboard.translate.pdfMode.textOnly": "仅文本", - "dashboard.translate.pdfMode.preserveLayoutDesc": "保留图片、表格和格式。适合简单PDF。", - "dashboard.translate.pdfMode.textOnlyDesc": "完美翻译所有文本。整洁输出,无排版问题。", - "dashboard.translate.pipeline.upload": "上传", - "dashboard.translate.pipeline.analyze": "分析", - "dashboard.translate.pipeline.translate": "翻译", - "dashboard.translate.pipeline.rebuild": "重建", - "dashboard.translate.pipeline.finalize": "完成", - "dashboard.translate.progress.processingFallback": "处理中…", - "dashboard.translate.progress.connectionLost": "连接已断开。正在重试…", - "dashboard.translate.progress.failedTitle": "翻译失败", - "dashboard.translate.error.unexpected": "发生了意外错误,请重试。", - "dashboard.translate.error.noResult": "翻译未产生结果。请确认文档包含文本,然后重试或选择其他引擎。", - "dashboard.translate.error.apiKey": "API 密钥无效或缺失。请联系管理员配置 API 密钥。", - "dashboard.translate.error.quota": "已达到使用限制。请稍后重试或选择其他引擎。", - "dashboard.translate.error.timeout": "翻译服务连接超时。请检查网络后重试。", - "dashboard.translate.error.sessionExpired": "会话已过期。点击重试以重新开始翻译。", - "dashboard.translate.error.empty": "文档似乎为空或不包含可翻译文本(扫描 PDF 图像?)。", - "dashboard.translate.error.unsupported": "不支持的文件格式或文件已损坏。", - "dashboard.translate.error.connection": "连接丢失。请检查网络后重试。", - "dashboard.translate.error.generic": "翻译失败:{detail}", - "dashboard.translate.error.title": "翻译失败", - "dashboard.translate.retry": "重试翻译", - "dashboard.translate.newFile": "新文件", - "dashboard.translate.modeAI": "AI 模式", - "dashboard.translate.modeClassic": "经典模式", - "dashboard.translate.glossaryLLMHint": "AI 模式下可使用术语表", - "dashboard.translate.submitting": "提交中...", - "dashboard.translate.submit": "开始翻译", - "dashboard.translate.noFile": "请先上传文件", - "dashboard.translate.noTargetLang": "请选择目标语言", - "glossaries.yourGlossaries": "您的术语表", - "glossaries.title": "术语表与上下文", - "glossaries.description": "管理您的术语表和上下文指令,以获得更准确的翻译。", - "glossaries.createNew": "新建", - "glossaries.empty": "暂无术语表", - "glossaries.emptyDesc": "创建您的第一个术语表或加载上方的专业预设", - "glossaries.defineTerms": "术语", - "glossaries.aboutTitle": "关于术语表", - "glossaries.aboutDesc": "术语表允许您为特定术语定义准确的翻译。翻译时,术语表中的术语可确保翻译的一致性和准确性。", - "glossaries.aboutFormat": "每个术语都有一个源词和多种语言的翻译。在翻译页面选择术语表即可应用。", - "glossaries.toast.created": "术语表已创建", - "glossaries.toast.createdDesc": "术语表\"{name}\"已创建。", - "glossaries.toast.imported": "术语表已导入", - "glossaries.toast.importedDesc": "术语表\"{name}\"已导入。", - "glossaries.toast.updated": "术语表已更新", - "glossaries.toast.updatedDesc": "术语表\"{name}\"已更新。", - "glossaries.toast.deleted": "术语表已删除", - "glossaries.toast.deletedDesc": "术语表已删除。", - "glossaries.toast.error": "错误", - "glossaries.toast.errorCreate": "创建术语表失败", - "glossaries.toast.errorImport": "导入术语表失败", - "glossaries.toast.errorUpdate": "更新术语表失败", - "glossaries.toast.errorDelete": "删除术语表失败", - "glossaries.dialog.title": "新建术语表", - "glossaries.dialog.description": "为您的翻译创建术语表", - "glossaries.dialog.nameLabel": "名称", - "glossaries.dialog.namePlaceholder": "我的术语表", - "glossaries.dialog.tabTemplates": "模板", - "glossaries.dialog.tabFile": "文件", - "glossaries.dialog.tabManual": "手动", - "glossaries.dialog.cancel": "取消", - "glossaries.dialog.creating": "正在创建…", - "glossaries.dialog.importing": "正在导入…", - "glossaries.dialog.importBtn": "导入", - "glossaries.dialog.selectPrompt": "选择", - "glossaries.dialog.createBtn": "创建", - "glossaries.dialog.createEmpty": "创建空表", - "glossaries.dialog.terms": "个术语", - "glossaries.dialog.templatesDesc": "选择预定义模板", - "glossaries.dialog.templatesEmpty": "暂无可用模板", - "glossaries.dialog.dropTitle": "将 CSV 文件拖到此处", - "glossaries.dialog.dropOr": "或", - "glossaries.dialog.dropFormats": "CSV、TSV、TXT", - "glossaries.termEditor.addTerm": "添加术语", - "glossaries.termEditor.maxReached": "每个术语表最多 {max} 个术语。", - "glossaries.dialog.formatTitle": "格式", - "glossaries.dialog.formatDesc": "源语言,目标语言(每行一对)", - "glossaries.dialog.formatNote": "如检测到表头则跳过首行", - "glossaries.dialog.errorFormat": "不支持的格式", - "glossaries.dialog.errorSize": "文件过大", - "glossaries.dialog.errorEmpty": "空文件", - "glossaries.dialog.errorRead": "读取错误", - "glossaries.dialog.parsing": "正在解析…", - "glossaries.dialog.termsImported": "个术语已导入", - "glossaries.dialog.changeFile": "更换文件", - "glossaries.dialog.retry": "重试", - "glossaries.edit.title": "Modifier le glossaire", - "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", - "glossaries.edit.nameLabel": "Nom du glossaire", - "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", - "glossaries.edit.sourceLang": "Langue source", - "glossaries.edit.targetLang": "Langue cible", - "glossaries.edit.termsLabel": "Termes ({count} valides)", - "glossaries.edit.exportCsv": "Exporter CSV", - "glossaries.edit.importCsv": "Importer CSV", - "glossaries.edit.cancel": "Annuler", - "glossaries.edit.saving": "Enregistrement...", - "glossaries.edit.saveChanges": "Enregistrer les modifications", - "glossaries.edit.importFailedTitle": "Échec de l'importation", - "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", - "glossaries.edit.importSuccessTitle": "Importation réussie", - "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", - "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", - "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", - "glossaries.delete.title": "Supprimer le glossaire", - "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", - "glossaries.delete.warning": "Cette action est irréversible", - "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", - "glossaries.delete.cancel": "Annuler", - "glossaries.delete.deleting": "Suppression...", - "glossaries.delete.deleteBtn": "Supprimer", - "glossaries.upgrade.title": "Glossaires", - "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", - "glossaries.upgrade.feature1": "Créez plusieurs glossaires", - "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", - "glossaries.upgrade.feature3": "Importez/exportez via CSV", - "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", - "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", - "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", - "glossaries.upgrade.proLabel": "Pro", - "glossaries.upgrade.upgradeBtn": "Passer à Pro", - "glossaries.loading": "Chargement...", - "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", - "glossaries.howItWorks.step1Title": "Configurez ici", - "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", - "glossaries.howItWorks.step2Title": "Activez dans Traduire", - "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", - "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", - "glossaries.howItWorks.goToTranslate": "Aller à Traduire", - "glossaries.status.unsaved": "Non enregistré", - "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", - "glossaries.status.inactive": "Inactif", - "glossaries.instructions.whatForBold": "À quoi ça sert ?", - "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", - "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", - "glossaries.instructions.charCount": "{count} caractères", - "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", - "glossaries.instructions.clearAll": "Tout effacer", - "glossaries.instructions.saving": "Enregistrement…", - "glossaries.instructions.saved": "Enregistré", - "glossaries.presets.whatForBold": "À quoi ça sert ?", - "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", - "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", - "glossaries.presets.creating": "Création…", - "glossaries.presets.alreadyImported": "Déjà importé", - "glossaries.presets.it.title": "IT / Logiciel", - "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", - "glossaries.presets.legal.title": "Juridique / Contrats", - "glossaries.presets.legal.desc": "Droit des affaires, contentieux", - "glossaries.presets.medical.title": "Médical / Santé", - "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", - "glossaries.presets.finance.title": "Finance / Comptabilité", - "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", - "glossaries.presets.marketing.title": "Marketing / Publicité", - "glossaries.presets.marketing.desc": "Digital, branding, analytics", - "glossaries.presets.hr.title": "RH / Ressources Humaines", - "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", - "glossaries.presets.scientific.title": "Scientifique / Recherche", - "glossaries.presets.scientific.desc": "Publications, thèses, articles", - "glossaries.presets.ecommerce.title": "E-commerce / Vente", - "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", - "glossaries.grid.title": "Vos", - "glossaries.grid.titleHighlight": "glossaires", - "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", - "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", - "glossaries.grid.activeTranslation": "Traduction active :", - "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", - "glossaries.badge.compatible": "Compatible", - "glossaries.badge.otherTarget": "Autre cible", - "glossaries.card.editTerms": "Modifier les termes", - "glossaries.card.created": "已创建", - "glossaries.card.term": "术语", - "glossaries.card.delete": "Supprimer", - "glossaries.grid.searchPlaceholder": "Search a glossary…", - "glossaries.grid.noResults": "No results for this search.", - "glossaries.detail.backToList": "Back to glossaries", - "glossaries.detail.save": "Save", - "glossaries.detail.savedTitle": "Saved", - "glossaries.detail.savedDesc": "The glossary has been updated.", - "glossaries.detail.settingsTitle": "Settings", - "glossaries.detail.sourceLang": "Source language", - "glossaries.detail.targetLang": "Target language", - "glossaries.detail.termsTitle": "Terms", - "glossaries.detail.terms": "terms", - "glossaries.detail.searchTerms": "Filter…", - "glossaries.detail.noTerms": "No terms yet.", - "glossaries.detail.addFirstTerm": "Add the first term", - "glossaries.detail.addTerm": "Add a term", - "glossaries.detail.maxReached": "Maximum limit reached", - "glossaries.detail.source": "Source", - "glossaries.detail.target": "Target", - "glossaries.detail.sourcePlaceholder": "source term", - "glossaries.detail.targetPlaceholder": "target term", - "glossaries.detail.csvTitle": "CSV", - "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", - "glossaries.detail.export": "Export", - "glossaries.detail.import": "Import", - "glossaries.detail.dangerTitle": "Danger zone", - "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", - "glossaries.detail.deleteGlossary": "Delete this glossary", - "glossaries.detail.confirmDelete": "Confirm deletion?", - "glossaries.detail.confirm": "Confirm", - "glossaries.detail.cancel": "Cancel", - "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", - "glossaries.detail.sourceLocked": "fixed", - "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", - "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", - "glossaries.detail.notFoundTitle": "Glossary not found", - "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", - "glossaries.detail.maxTermsTitle": "Limit reached", - "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", - "glossaries.detail.importEmptyTitle": "Empty file", - "glossaries.detail.importEmptyDesc": "No terms detected in this file.", - "glossaries.detail.importedTitle": "Imported", - "glossaries.detail.importedDesc": "{count} terms imported.", - "glossaries.detail.importErrorTitle": "Read error", - "glossaries.detail.importErrorDesc": "Unable to read the file.", - "apiKeys.webhook.title": "Intégration Webhook", - "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", - "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", - "apiKeys.webhook.codeParam": "webhook_url", - "translate.mode.label": "Mode de traduction", - "translate.mode.classic": "Classique", - "translate.mode.classicDesc": "Rapide", - "translate.mode.proLlm": "Pro LLM", - "translate.mode.proLlmDesc": "Contextuel", - "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", - "translate.mode.upgradeLink": "Passer à Pro", - "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", - "pricing.nav.back": "返回", - "pricing.nav.home": "首页", - "pricing.nav.mySubscription": "我的订阅", - "pricing.header.badge": "AI 模型已更新 — 2026年3月", - "pricing.header.title": "满足各种需求的方案", - "pricing.header.subtitle": "翻译 Word、Excel 和 PowerPoint 文档,同时保留原始排版。无需 API 密钥。", - "pricing.billing.monthly": "月付", - "pricing.billing.yearly": "年付", - "pricing.plans.free.name": "免费", - "pricing.plans.starter.name": "入门版", - "pricing.plans.pro.name": "专业版", - "pricing.plans.business.name": "企业版", - "pricing.plans.enterprise.name": "旗舰版", - "pricing.plans.free.description": "非常适合体验应用", - "pricing.plans.starter.description": "面向个人和小型项目", - "pricing.plans.pro.description": "面向专业人士和成长中的团队", - "pricing.plans.business.description": "面向团队和组织", - "pricing.plans.enterprise.description": "为大型组织提供定制解决方案", - "pricing.plans.pro.highlight": "最受欢迎", - "pricing.plans.pro.badge": "热门", - "pricing.plans.enterprise.badge": "按需报价", - "pricing.plans.free.feat1": "每月 5 份文档", - "pricing.plans.free.feat2": "每份文档最多 15 页", - "pricing.plans.free.feat3": "包含 Google 翻译", - "pricing.plans.free.feat4": "支持所有语言(130+)", - "pricing.plans.free.feat5": "社区支持", - "pricing.plans.starter.feat1": "每月 50 份文档", - "pricing.plans.starter.feat2": "每份文档最多 50 页", - "pricing.plans.starter.feat3": "Google 翻译 + DeepL", - "pricing.plans.starter.feat4": "文件最大 10 MB", - "pricing.plans.starter.feat5": "邮件支持", - "pricing.plans.starter.feat6": "30 天历史记录", - "pricing.plans.pro.feat1": "每月 200 份文档", - "pricing.plans.pro.feat2": "每份文档最多 200 页", - "pricing.plans.pro.feat3": "Essential AI翻译", - "pricing.plans.pro.feat4": "Google 翻译 + DeepL", - "pricing.plans.pro.feat5": "文件最大 25 MB", - "pricing.plans.pro.feat6": "自定义术语表", - "pricing.plans.pro.feat7": "优先支持", - "pricing.plans.pro.feat8": "90 天历史记录", - "pricing.plans.business.feat1": "每月 1,000 份文档", - "pricing.plans.business.feat2": "每份文档最多 500 页", - "pricing.plans.business.feat3": "基础 + 高级 AI(Claude Haiku)", - "pricing.plans.business.feat4": "所有翻译服务商", - "pricing.plans.business.feat5": "文件最大 50 MB", - "pricing.plans.business.feat6": "API 访问(每月 10,000 次调用)", - "pricing.plans.business.feat7": "通知 Webhook", - "pricing.plans.business.feat8": "专属支持", - "pricing.plans.business.feat9": "1 年历史记录", - "pricing.plans.business.feat10": "高级分析", - "pricing.plans.enterprise.feat1": "无限文档", - "pricing.plans.enterprise.feat2": "所有 AI 模型(GPT-5、Claude Opus 4.6…)", - "pricing.plans.enterprise.feat3": "本地部署或专属云", - "pricing.plans.enterprise.feat4": "99.9% SLA 保障", - "pricing.plans.enterprise.feat5": "24/7 专属支持", - "pricing.plans.enterprise.feat6": "白标(White-label)", - "pricing.plans.enterprise.feat7": "无限团队", - "pricing.plans.enterprise.feat8": "定制集成", - "pricing.card.onRequest": "按需报价", - "pricing.card.free": "免费", - "pricing.card.perMonth": "/月", - "pricing.card.billedYearly": "按年计费 {price} €", - "pricing.card.documents": "文档", - "pricing.card.pagesMax": "最大页数", - "pricing.card.aiTranslation": "AI 翻译", - "pricing.card.unlimited": "无限", - "pricing.card.perMonthStat": "/ 月", - "pricing.card.perDoc": "页 / 文档", - "pricing.card.aiEssential": "基础版", - "pricing.card.aiEssentialPremium": "基础版 + 高级版", - "pricing.card.aiCustom": "定制", - "pricing.card.myPlan": "我的方案", - "pricing.card.managePlan": "管理方案", - "pricing.card.startFree": "免费开始", - "pricing.card.contactUs": "联系我们", - "pricing.card.choosePlan": "选择此方案", - "pricing.card.processing": "处理中…", - "pricing.comparison.title": "详细对比", - "pricing.comparison.subtitle": "各方案包含的所有功能", - "pricing.comparison.feature": "功能", - "pricing.comparison.docsPerMonth": "文档 / 月", - "pricing.comparison.pagesMaxPerDoc": "最大页数 / 文档", - "pricing.comparison.maxFileSize": "最大文件大小", - "pricing.comparison.googleTranslation": "Google 翻译", - "pricing.comparison.deepl": "DeepL", - "pricing.comparison.aiEssential": "基础 AI 翻译", - "pricing.comparison.aiPremium": "高级 AI 翻译", - "pricing.comparison.apiAccess": "API 访问", - "pricing.comparison.priorityProcessing": "优先处理", - "pricing.comparison.support": "支持", - "pricing.comparison.support.community": "社区", - "pricing.comparison.support.email": "邮件", - "pricing.comparison.support.priority": "优先", - "pricing.comparison.support.dedicated": "专属", - "pricing.comparison.mb": "MB", - "pricing.credits.title": "额外额度", - "pricing.credits.subtitle": "需要更多?单独购买额度,无需订阅。", - "pricing.credits.perPage": "1 额度 = 1 翻译页。", - "pricing.credits.bestValue": "最划算", - "pricing.credits.unit": "额度", - "pricing.credits.centsPerCredit": "分 / 额度", - "pricing.credits.buy": "购买", - "pricing.trust.encryption.title": "端到端加密", - "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 静态加密", - "pricing.trust.languages.title": "130+ 种语言", - "pricing.trust.languages.sub": "包括阿拉伯语、波斯语、希伯来语(RTL)", - "pricing.trust.parallel.title": "并行处理", - "pricing.trust.parallel.sub": "超快多线程 AI", - "pricing.trust.availability.title": "7×24 小时可用", - "pricing.trust.availability.sub": "99.9% 可用性保障", - "pricing.aiModels.title": "我们的 AI 模型 — 2026年3月", - "pricing.aiModels.essential.title": "基础 AI 翻译", - "pricing.aiModels.essential.plan": "专业版方案", - "pricing.aiModels.essential.descPrefix": "基于", - "pricing.aiModels.essential.descSuffix": "— 2026 年最具性价比的 AI 模型。质量媲美前沿模型,成本仅为其一小部分。", - "pricing.aiModels.essential.modelName": "Essential AI模型", - "pricing.aiModels.essential.context": "163K 上下文 Token", - "pricing.aiModels.essential.value": "性价比极佳", - "pricing.aiModels.premium.title": "高级 AI 翻译", - "pricing.aiModels.premium.plan": "企业版方案", - "pricing.aiModels.premium.descPrefix": "基于", - "pricing.aiModels.premium.descSuffix": "Anthropic 出品 — 在法律、医疗和复杂技术文档方面表现精准。", - "pricing.aiModels.premium.context": "200K 上下文 Token", - "pricing.aiModels.premium.precision": "最高精度", - "pricing.faq.title": "常见问题", - "pricing.faq.q1": "我可以随时更换方案吗?", - "pricing.faq.a1": "可以。升级立即生效并按比例计费。降级在当前周期结束时生效。", - "pricing.faq.q2": "什么是「基础 AI 翻译」?", - "pricing.faq.a2": "这是我们的AI引擎。它能理解文档上下文,保留排版,并比传统翻译更好地处理技术术语。", - "pricing.faq.q3": "基础 AI 和高级 AI 有什么区别?", - "pricing.faq.a3": "Essential AI使用优化模型(性价比极佳)。Premium AI使用Anthropic的Claude 3.5 Haiku,在法律、医学和复杂技术文档上更准确。", - "pricing.faq.q4": "翻译后文档会被保留吗?", - "pricing.faq.a4": "翻译文件根据您的方案保留(入门版 30 天、专业版 90 天、企业版 1 年)。存储和传输过程中均已加密。", - "pricing.faq.q5": "超过月度配额会怎样?", - "pricing.faq.a5": "You can buy additional credits individually, or upgrade your plan.", - "pricing.faq.q6": "付费方案有免费试用吗?", - "pricing.faq.a6": "免费方案永久有效且无需信用卡。专业版和企业版方案请联系我们获取 14 天试用。", - "pricing.faq.q7": "支持哪些文件格式?", - "pricing.faq.a7": "Word(.docx)、Excel(.xlsx/.xls)、PowerPoint(.pptx),即将支持 PDF。所有方案支持相同的格式。", - "pricing.cta.title": "准备好开始了吗?", - "pricing.cta.subtitle": "免费开始,无需信用卡。需要时再升级。", - "pricing.cta.createAccount": "创建免费账户", - "pricing.cta.login": "登录", - "pricing.toast.demo": "演示模式 — Stripe 尚未配置。在生产环境中,您将被重定向至支付页面以激活 {planId} 方案。", - "pricing.toast.networkError": "网络错误,请重试。", - "pricing.toast.paymentError": "创建支付时出错。", - "register.title": "创建账户", - "register.subtitle": "免费开始翻译", - "register.error.failed": "注册失败", - "register.name.label": "姓名", - "register.name.placeholder": "您的姓名", - "register.name.error": "姓名至少需要 2 个字符", - "register.email.label": "电子邮箱", - "register.email.placeholder": "you@example.com", - "register.email.error": "无效的邮箱地址", - "register.password.label": "密码", - "register.password.error": "密码至少需要 8 个字符,包含大写字母、小写字母和数字", - "register.password.show": "显示密码", - "register.password.hide": "隐藏密码", - "register.password.strengthLabel": "强度:", - "register.password.strength.weak": "弱", - "register.password.strength.medium": "中", - "register.password.strength.strong": "强", - "register.confirmPassword.label": "确认密码", - "register.confirmPassword.error": "两次输入的密码不一致", - "register.confirmPassword.show": "显示", - "register.confirmPassword.hide": "隐藏", - "register.submit.creating": "正在创建账户...", - "register.submit.create": "创建我的账户", - "register.hasAccount": "已有账户?", - "register.login": "登录", - "register.terms.prefix": "创建账户即表示您接受我们的", - "register.terms.link": "服务条款", - - "common.loading": "加载中...", - "profile.header.title": "我的资料", - "profile.header.subtitle": "管理您的账户和偏好设置。", - "profile.tabs.account": "账户", - "profile.tabs.subscription": "订阅", - "profile.tabs.preferences": "偏好设置", - "profile.account.user": "用户", - "profile.account.memberSince": "注册时间", - "profile.plan.label": "套餐", - "profile.plan.free": "Free", - "profile.plan.starter": "Starter", - "profile.plan.pro": "Pro", - "profile.plan.business": "Business", - "profile.plan.enterprise": "Enterprise", - "profile.plan.pricePerMonth": "{price} €/月", - "profile.subscription.canceling": "取消中", - "profile.subscription.active": "有效", - "profile.subscription.unknown": "未知", - "profile.subscription.accessUntil": "访问截止日期", - "profile.subscription.renewalOn": "续费日期", - "profile.subscription.upgradePlan": "升级到付费套餐", - "profile.subscription.changePlan": "更改套餐", - "profile.subscription.manageBilling": "管理账单", - "profile.subscription.billingUnavailable": "账单门户不可用。", - "profile.subscription.billingError": "访问账单门户时出错。", - "profile.subscription.cancelSuccess": "订阅已取消。您可以继续使用至本期结束。", - "profile.subscription.cancelError": "取消时出错。", - "profile.subscription.networkError": "网络错误。", - "profile.usage.title": "本月使用量", - "profile.usage.resetOn": "重置日期", - "profile.usage.documents": "文档", - "profile.usage.pages": "页数", - "profile.usage.extraCredits": "额外额度", - "profile.usage.extraCreditsPlural": "额外额度", - "profile.usage.quotaReached": "配额已用完", - "profile.usage.quotaReachedDesc": "升级到更高套餐以继续使用。", - "profile.usage.unlockMore": "升级付费套餐以获取更多翻译。", - "profile.usage.viewPlans": "查看套餐", - "profile.usage.includedInPlan": "已包含在您的套餐中", - "profile.danger.title": "危险区域", - "profile.danger.description": "取消将在当前周期结束时生效。在此之前您可以继续使用。", - "profile.danger.confirm": "确定要继续吗?此操作不可撤销。", - "profile.danger.confirmCancel": "确认取消", - "profile.danger.cancelSubscription": "取消我的订阅", - "profile.danger.keep": "不,保留", - "profile.prefs.interfaceLang": "界面语言", - "profile.prefs.interfaceLangDesc": "语言会根据您的浏览器自动检测。您也可以手动更改。", - "profile.prefs.defaultTargetLang": "默认目标语言", - "profile.prefs.selectLanguage": "选择语言", - "profile.prefs.defaultTargetLangDesc": "翻译时将自动选择此语言。", - "profile.prefs.save": "保存", - "profile.prefs.theme": "主题", - "profile.prefs.themeDesc": "选择界面外观", - "profile.prefs.cache": "缓存", - "profile.prefs.cacheDesc": "清除本地缓存可以修复一些显示问题。", - "profile.prefs.clearing": "清除中...", - "profile.prefs.clearCache": "清除缓存", - "settings.title": "设置", - "settings.subtitle": "通用应用配置", - "settings.formats.title": "支持的格式", - "settings.formats.subtitle": "您可以翻译的文档类型", - "settings.formats.formulas": "公式", - "settings.formats.styles": "样式", - "settings.formats.images": "图片", - "settings.formats.headers": "页眉", - "settings.formats.tables": "表格", - "settings.formats.slides": "幻灯片", - "settings.formats.notes": "备注", - "settings.cache.title": "缓存", - "settings.cache.desc": "清除本地缓存可以修复一些显示问题。", - "settings.cache.clearing": "清除中...", - "settings.cache.clear": "清除缓存", - "services.title": "翻译服务提供商", - "services.subtitle": "服务提供商由管理员配置。您可以查看当前账户可用的提供商。", - "services.loading": "正在加载提供商...", - "services.noProviders": "当前没有配置任何提供商。请联系管理员。", - "services.classic": "经典翻译", - "services.llmPro": "LLM · 上下文感知 (Pro)", - "services.available": "可用", - "services.model": "模型", - "services.adminOnly.title": "提供商配置仅限管理员", - "services.adminOnly.desc": "API 密钥、模型选择和提供商激活由管理员在管理面板中管理。您无需输入 API 密钥。", - "apiKeys.title": "API 密钥", - "apiKeys.subtitle": "管理用于编程访问翻译 API 的 API 密钥。", - "apiKeys.loading": "加载中...", - "apiKeys.sectionTitle": "API 与自动化", - "apiKeys.sectionDesc": "生成和管理用于自动化工作流的 API 密钥", - "apiKeys.keysUsed": "已使用 {total} / {max} 个密钥", - "apiKeys.maxReached": "已达到密钥上限。请吊销现有密钥后再生成新密钥。", - "apiKeys.canGenerate": "还可以生成 {count} 个密钥", - "apiKeys.canGeneratePlural": "还可以生成 {count} 个密钥", - "apiKeys.generateNew": "生成新密钥", - "apiKeys.keyRevoked": "密钥已吊销", - "apiKeys.keyRevokedDesc": "API 密钥已成功吊销。", - "apiKeys.keyNotFound": "密钥未找到", - "apiKeys.keyNotFoundDesc": "API 密钥已不存在。可能已被吊销。", - "apiKeys.error": "错误", - "apiKeys.revokeError": "吊销 API 密钥失败。请重试。", - "apiKeys.limitReached": "已达上限", - "apiKeys.limitReachedDesc": "您已达到最多 10 个 API 密钥的限制。请吊销现有密钥后再生成新密钥。", - "apiKeys.proRequired": "需要 Pro 功能", - "apiKeys.proRequiredDesc": "API 密钥是 Pro 功能。请升级您的账户。", - "apiKeys.generateError": "生成 API 密钥失败。请重试。", - "apiKeys.upgrade.title": "API 密钥", - "apiKeys.upgrade.subtitle": "通过 API 访问自动化翻译", - "apiKeys.upgrade.feat1": "生成无限 API 密钥", - "apiKeys.upgrade.feat2": "自动化文档翻译", - "apiKeys.upgrade.feat3": "Webhook 通知", - "apiKeys.upgrade.feat4": "LLM 翻译模式", - "apiKeys.upgrade.proFeature": "API 密钥是{pro}功能。升级以解锁 API 自动化。", - "apiKeys.upgrade.pro": "Pro", - "apiKeys.upgrade.cta": "升级到 Pro", - "apiKeys.dialog.maxTitle": "已达最大密钥数", - "apiKeys.dialog.maxDesc": "您已达到最多 10 个 API 密钥的限制。请在生成新密钥前吊销现有密钥。", - "apiKeys.dialog.close": "关闭", - "apiKeys.dialog.generated": "API 密钥已生成!", - "apiKeys.dialog.generatedDesc": "新的 API 密钥已创建。请立即复制 - 之后将不再显示。", - "apiKeys.dialog.important": "重要提示:", - "apiKeys.dialog.importantDesc": "这是您唯一一次看到此密钥。请妥善保存。", - "apiKeys.dialog.apiKey": "API 密钥", - "apiKeys.dialog.name": "名称:", - "apiKeys.dialog.done": "完成", - "apiKeys.dialog.copied": "我已复制密钥", - "apiKeys.dialog.generateTitle": "生成新 API 密钥", - "apiKeys.dialog.generateDesc": "创建用于编程访问翻译 API 的新 API 密钥。", - "apiKeys.dialog.keyName": "密钥名称(可选)", - "apiKeys.dialog.keyNamePlaceholder": "例如:生产环境、测试环境", - "apiKeys.dialog.keyNameHint": "一个描述性的名称,方便您以后识别此密钥。", - "apiKeys.dialog.nameTooLong": "名称不得超过 {max} 个字符", - "apiKeys.dialog.nameInvalid": "名称只能包含字母、数字、空格、连字符和下划线", - "apiKeys.dialog.cancel": "取消", - "apiKeys.dialog.generating": "生成中...", - "apiKeys.dialog.generate": "生成密钥", - "apiKeys.table.name": "名称", - "apiKeys.table.prefix": "前缀", - "apiKeys.table.created": "创建时间", - "apiKeys.table.lastUsed": "最后使用", - "apiKeys.table.never": "从未使用", - "apiKeys.table.actions": "操作", - "apiKeys.table.revoke": "吊销", - "apiKeys.table.copyPrefix": "复制密钥前缀", - "apiKeys.table.revokeKey": "吊销密钥", - "apiKeys.revokeDialog.title": "吊销 API 密钥", - "apiKeys.revokeDialog.desc": "确定要吊销密钥\"{name}\"吗?此操作不可撤销。", - "apiKeys.revokeDialog.confirm": "是,吊销", - "apiKeys.revokeDialog.cancel": "取消", - "context.proTitle": "Pro 功能", - "context.proDesc": "上下文和专业术语表适用于 Pro、Business 和 Enterprise 套餐。它们通过特定领域的指令和词汇提供更准确的翻译。", - "context.viewPlans": "查看套餐", - "context.title": "上下文与术语表", - "context.subtitle": "通过特定领域的指令和词汇提高翻译质量。", - "context.presets.title": "专业术语表", - "context.presets.desc": "加载包含指令和专业术语的完整术语表", - "context.instructions.title": "上下文指令", - "context.instructions.desc": "翻译过程中 AI 将遵循的指令", - "context.instructions.placeholder": "例如:您翻译 HVAC 技术文档。请使用精确的工程术语...", - "context.glossary.title": "技术术语表", - "context.glossary.desc": "格式:source=target(每行一个)。通过预设加载的术语表可编辑。", - "context.glossary.terms": "术语表中的术语数", - "context.clearAll": "全部清除", - "context.saving": "保存中...", - "context.save": "保存", - "translate.glossary.title": "术语表", - "translate.glossary.select": "选择术语表", - "translate.glossary.none": "无", - "translate.glossary.terms": "个术语", - "translate.glossary.proOnly": "升级到Pro以使用术语表", - "translate.glossary.myGlossaries": "我的术语表", - "translate.glossary.fromTemplate": "从模板创建", - "translate.glossary.noGlossaryForPair": "无术语表", - "translate.glossary.noGlossaries": "无术语表", - "translate.glossary.loading": "加载中...", - "translate.glossary.classicMode": "无术语表的中性引擎(仅AI)", - "translate.glossary.selectPlaceholder": "选择术语表...", - "translate.glossary.multilingual": "多语言", - "translate.glossary.noGlossaryAvailable": "无可用术语表", - "translate.glossary.filterByLang": "按语言筛选", - "translate.glossary.active": "启用", - "translate.glossary.inactive": "未启用", - "translate.glossary.availableTemplates": "可用模板", - "translate.glossary.importing": "导入中...", - "translate.glossary.imported": "(已导入)", - "translate.glossary.noGlossaryForSource": "源语言无术语表或模板", - "translate.glossary.createGlossary": "创建术语表", - "translate.glossary.showAll": "显示所有术语表", - "translate.glossary.activePreview": "活跃匹配预览:", - "translate.glossary.total": "总计", - "translate.glossary.moreTerms": "其他术语", - "translate.glossary.noTerms": "此术语表中没有术语。", - "translate.glossary.sourceTerm": "源术语", - "translate.glossary.translation": "翻译", - "translate.glossary.addTerm": "添加术语", - "translate.glossary.disabledMode": "无术语表应用的中性引擎", - "translate.glossary.addTermError": "添加术语时出错", - "translate.glossary.networkError": "网络错误", - "translate.glossary.importFailed": "导入失败 ({status})", - "translate.glossary.helpText": "术语表强制精确的术语翻译。请选择源语言与文档原始语言匹配的术语表。", - "translate.glossary.sourceWarning": "注意:此术语表使用源语言", - "translate.glossary.sourceWarningBut": "但您的文档配置为", - "translate.glossary.targetWarning": "目标不匹配:此术语表旨在翻译为", - "translate.glossary.targetWarningBut": "但您的文档目标为", - "translate.glossary.targetWarningEnd": "术语可能不相关。", - "context.presets.createGlossary": "创建术语表", - "context.presets.created": "术语表已创建", - "context.presets.createdDesc": "术语表 \"{name}\" 已创建,包含 {count} 个术语。", - "context.presets.hint": "点击预设以创建包含领域特定术语的术语表。在术语表部分管理您的术语表。", - "context.glossary.manage": "管理术语表", - "context.saved": "已保存", - "context.savedDesc": "您的上下文说明已保存。", - "admin.login.title": "管理后台", - "admin.login.required": "需要登录", - "admin.login.password": "管理员密码", - "admin.login.connecting": "连接中...", - "admin.login.access": "进入管理面板", - "admin.login.restricted": "仅限管理员", - "admin.layout.checking": "正在验证身份...", - "admin.dashboard.title": "管理仪表盘", - "admin.dashboard.subtitle": "管理员控制面板", - "admin.dashboard.refresh": "刷新", - "admin.dashboard.refreshTooltip": "刷新仪表盘数据", - "admin.dashboard.config": "系统配置", - "admin.dashboard.maxFileSize": "最大文件大小:", - "admin.dashboard.translationService": "翻译服务:", - "admin.dashboard.formats": "支持格式:", - "admin.nav.dashboard": "Dashboard", - "admin.nav.users": "用户", - "admin.nav.pricing": "定价 & Stripe", - "admin.nav.providers": "服务商", - "admin.nav.system": "系统", - "admin.nav.logs": "日志", - "admin.users.title": "用户管理", - "admin.users.subtitle": "查看和管理用户账户", - "admin.users.planUpdated": "套餐已更新", - "admin.users.planChanged": "套餐已成功更改为\"{plan}\"。", - "admin.users.unknownError": "未知错误", - "admin.users.error": "错误", - "admin.users.planUpdateError": "无法更新套餐:{message}", - "admin.users.noKeys": "无密钥", - "admin.users.noKeysDesc": "该用户没有有效的API密钥。", - "admin.users.keysRevoked": "密钥已撤销", - "admin.users.keysRevokedDesc": "{count}个API密钥已成功撤销。", - "admin.users.revokeError": "无法撤销密钥:{message}", - "admin.users.retry": "重试", - "admin.system.title": "系统", - "admin.system.subtitle": "监控系统状态并管理资源", - "admin.system.quotas": "翻译配额", - "admin.system.resetQuotas": "重置月度配额", - "admin.system.resetting": "重置中...", - "admin.system.reset": "重置", - "admin.system.allOperational": "所有系统正常运行", - "admin.system.issuesDetected": "检测到系统问题", - "admin.system.waitingData": "等待数据...", - "admin.system.purging": "清理中...", - "admin.system.clean": "清理", - "admin.system.purge": "清除", - "memento.title": "探索 Momento", - "memento.slogan": "Momento 不仅仅是一个笔记应用。它是一个智能生态系统,利用 6 个 AI 代理和先进的语义搜索,实时连接、分析和发展您的想法。", - "memento.ctaFree": "免费开始", - "memento.ctaMore": "了解更多", - "common.backToHome": "返回首页", - "dashboard.topbar.interfaceLabel": "翻译界面", - "dashboard.topbar.premiumAccess": "高级访问", - "landing.hero.contextEngine": "检测到翻译:HVAC 系统技术维护术语...", - "landing.hero.liveAnalysis": "实时分析", - "landing.hero.termsDetected": "个术语已检测", - "landing.steps.process": "流程", - "landing.translate.newProject": "新项目", - "landing.translate.title": "翻译文档", - "landing.translate.subtitle": "导入文件并选择目标语言", - "landing.translate.sourceDocument": "源文档", - "landing.translate.configuration": "配置", - "landing.translate.sourceLang": "源语言", - "landing.translate.targetLang": "目标语言", - "landing.translate.provider": "提供商", - "landing.translate.startTranslation": "开始翻译", - "landing.translate.zeroRetention": "零保留", - "landing.translate.filesDeleted": "处理后删除文件", - "landing.translate.dropHere": "拖放到此处", - "landing.translate.supportedFormats": "支持 DOCX, XLSX, PPTX 或 PDF 文件", - "landing.translate.aiAnalysis": "AI 分析中", - "landing.translate.processing": "正在处理", - "landing.translate.preservingLayout": "正在保留您的排版", - "layout.nav.apiAccess": "API 访问", - "layout.footer.terms": "条款", - "layout.footer.privacy": "隐私", - "fileUploader.uploadDocument": "上传文档", - "fileUploader.uploadDesc": "拖放或点击选择文件 (Excel, Word, PowerPoint)", - "fileUploader.dropHere": "将文件拖到此处…", - "fileUploader.dragAndDrop": "将文档拖到此处", - "fileUploader.orClickBrowse": "或点击浏览", - "fileUploader.preview": "预览", - "fileUploader.translationOptions": "翻译选项", - "fileUploader.configureSettings": "配置翻译设置", - "fileUploader.targetLanguage": "目标语言", - "fileUploader.selectLanguage": "选择语言", - "fileUploader.translationProvider": "翻译服务提供商", - "fileUploader.selectProvider": "选择提供商", - "fileUploader.advancedOptions": "高级选项", - "fileUploader.translateImages": "翻译图片", - "fileUploader.translating": "翻译中…", - "fileUploader.translateDocument": "翻译文档", - "fileUploader.processing": "处理中…", - "fileUploader.translationError": "翻译错误", - "fileUploader.translationComplete": "翻译完成!", - "fileUploader.translationCompleteDesc": "您的文档已成功翻译,并保留了所有格式。", - "fileUploader.download": "下载翻译后的文档", - "fileUploader.webgpuUnsupported": "此浏览器不支持 WebGPU。请使用 Chrome 113+ 或 Edge 113+。", - "fileUploader.webllmNotLoaded": "WebLLM 模型未加载。请前往设置 > 翻译服务 加载模型。", - "fileUploader.extracting": "正在从文档中提取文本…", - "fileUploader.noTranslatable": "文档中未找到可翻译的文本", - "fileUploader.foundTexts": "找到 {count} 个要翻译的文本", - "fileUploader.translatingItem": "正在翻译 {current}/{total}: \"{preview}\"", - "fileUploader.reconstructing": "正在重建文档…", - "fileUploader.translatingLocally": "正在使用 WebLLM 本地翻译…", - "checkout.activating": "正在激活…", - "checkout.activatingDesc": "我们正在更新您的订阅,请稍候。", - "checkout.paymentConfirmed": "支付已确认!", - "checkout.subscriptionActivated": "订阅已激活!", - "checkout.planActivated": "{plan} 套餐已激活!", - "checkout.redirectingToProfile": "正在跳转到您的个人资料…", - "checkout.paymentReceived": "已收到付款", - "checkout.redirecting": "正在跳转…", - "checkout.syncError": "同步错误", - "checkout.networkError": "网络错误。您的付款已确认 — 请重新加载您的个人资料。", - "dashboard.checkoutSyncError": "同步付款时出错。", - "dashboard.networkRefresh": "网络错误。请刷新页面。", - "dashboard.continueToTranslate": "继续翻译", - "langSelector.search": "搜索…", - "langSelector.noResults": "无结果", - "langSelector.source": "源", - "langSelector.target": "目标", - "langSelector.swap": "交换", - "translateComplete.highQuality": "高质量", - "translateComplete.segments": "段落", - "translateComplete.characters": "字符", - "translateComplete.confidence": "置信度", - "providerTheme.deepseek.badge": "基础", - "providerTheme.deepseek.subBadge": "技术与经济", - "providerTheme.deepseek.desc": "超精准且经济的翻译,非常适合技术文档和代码。", - "providerTheme.openai.badge": "高级", - "providerTheme.openai.subBadge": "高保真", - "providerTheme.openai.desc": "全球 AI 标准。最大化的文本一致性和严格的风格尊重。", - "providerTheme.minimax.badge": "高级", - "providerTheme.minimax.subBadge": "性能", - "providerTheme.minimax.desc": "惊人的执行速度和对复杂结构的出色理解。", - "providerTheme.openrouter.badge": "快速", - "providerTheme.openrouter.subBadge": "多模型", - "providerTheme.openrouter.desc": "统一访问为翻译优化的最佳开源模型。", - "providerTheme.openrouter_premium.badge": "超级", - "providerTheme.openrouter_premium.subBadge": "最大上下文", - "providerTheme.openrouter_premium.desc": "由尖端模型(GPT-4o、Claude Sonnet 4.6)辅助,适用于长文档。", - "providerTheme.zai.badge": "专业", - "providerTheme.zai.subBadge": "金融与法律", - "providerTheme.zai.desc": "针对苛刻的业务术语(法律、金融)进行了微调的模型。", - "providerTheme.default.badge": "现代", - "providerTheme.default.subBadge": "AI 推理", - "providerTheme.default.desc": "大型语言模型 (LLM) 翻译,具有高级语义分析。", - "providerTheme.classic.google.label": "Google 翻译", - "providerTheme.classic.google.desc": "覆盖 130 多种语言的超快速翻译。建议用于一般流程。", - "providerTheme.classic.deepl.label": "DeepL Pro", - "providerTheme.classic.deepl.desc": "以流畅和自然的措辞著称的高精度翻译。", - "providerTheme.classic.google_cloud.label": "Google Cloud API", - "providerTheme.classic.google_cloud.desc": "针对处理大量文档进行优化的专业云端引擎。", - "providerSelector.noClassic": "没有可用的标准翻译器。", - "providerSelector.noLlm": "未配置 AI 模型。", - "providerSelector.costOne": "费用:每页 1 积分", - "providerSelector.costFive": "费用:每页 5 积分(高级系数)", - "providerSelector.unlockContextual": "为您的整个文档解锁高级上下文翻译。", - "translate.header.processing": "正在处理", - "translate.header.aiActive": "AI 分析已激活", - "translate.header.aiActiveDesc": "您的布局正在由我们的上下文引擎保留。", - "translate.header.completed": "已完成", - "translate.header.completedTitle": "翻译完成", - "translate.header.proSpace": "专业版空间", - "translate.header.translateDoc": "翻译文档", - "translate.header.translateDocDesc": "通过我们超高保真度翻译引擎保留原始布局。", - "translate.upload.nativeFormat": "原生格式", - "translate.fileType.word": "Word (.docx)", - "translate.fileType.excel": "Excel (.xlsx)", - "translate.fileType.slides": "幻灯片 (.pptx)", - "translate.fileType.pdf": "PDF (.pdf)", - "translate.startTranslation": "开始翻译", - "translate.submit": "提交中…", - "translate.chooseTargetLang": "请选择目标语言", - "translate.pleaseLoadFile": "请先上传文件", - "translate.contextEngineActive": "上下文引擎已激活", - "translate.phase1": "阶段 1:初始化", - "translate.phase2": "阶段 2:上下文重建", - "translate.stat.segments": "段落", - "translate.stat.precision": "精度", - "translate.stat.speedLabel": "速度", - "translate.stat.turbo": "极速", - "translate.stat.time": "时间", - "translate.complete.masterQuality": "✓ 大师级品质", - "translate.download": "下载", - "translate.newTranslation": "+ 新建翻译", - "translate.failedTitle": "翻译错误", - "translate.retry": "重试", - "translate.uploadAnother": "上传其他文件", - "translate.monitor": "AI 监控", - "translate.summary": "摘要", - "translate.cancelProcess": "⟳ 取消流程", - "translate.layoutIntegrity": "布局完整性", - "translate.secureHundred": "100% 安全", - "translate.okHundred": "100% OK", - "translate.preserveLayout": "保留布局", - "translate.preserveLayoutDesc": "保留布局", - "translate.textOnly": "仅文本", - "translate.textOnlyDesc": "仅文本快速翻译", - "translate.unavailableStandard": "标准模式下不可用(仅 AI)", - "apiKeys.noKeysGenerated": "未生成密钥", - "apiKeys.copied": "已复制!", - "services.fallback.google.label": "Google 翻译", - "services.fallback.google.desc": "快速翻译,130 多种语言", - "settings.formats.excel.name": "Excel", - "settings.formats.word.name": "Word", - "settings.formats.powerpoint.name": "PowerPoint", - "pricing.dashboard": "仪表板", - "pricing.okSymbol": "✓", - "pricing.errSymbol": "✕", - }, - - // ARABIC (ar) - // ═══════════════════════════════════════════════════════════════ - ar: { - "auth.brandName": "Wordly", - "dashboard.nav.translate": "ترجمة", - "dashboard.nav.profile": "ملفي الشخصي", - "dashboard.nav.settings": "الإعدادات", - "dashboard.nav.context": "السياق", - "dashboard.nav.services": "الخدمات", - "dashboard.nav.apiKeys": "مفاتيح API", - "dashboard.nav.glossaries": "المعاجم", - "dashboard.header.title": "لوحة التحكم", - "dashboard.header.subtitle": "إدارة ترجماتك", - "dashboard.header.toggleMenu": "القائمة", - "dashboard.header.profileTitle": "ملفي الشخصي", - "dashboard.sidebar.theme": "المظهر", - "dashboard.sidebar.signOut": "تسجيل الخروج", - "dashboard.sidebar.backHome": "العودة إلى الصفحة الرئيسية", - "dashboard.sidebar.upgradeToPro": "الترقية إلى Pro ←", - "cookieConsent.title": "ملفات تعريف الارتباط على Wordly", - "cookieConsent.description": "نستخدم ملفات تعريف الارتباط الأساسية لعمل التطبيق (الجلسة، الأمان، اللغة). بإذنك، نستخدم أيضًا ملفات تعريف ارتباط اختيارية لقياس حركة المرور وتحسين المنتج.", - "cookieConsent.acceptAll": "قبول الكل", - "cookieConsent.essentialOnly": "الأساسية فقط", - "cookieConsent.learnMore": "معرفة المزيد", - "login.orContinueWith": "أو تابع بالبريد الإلكتروني", - "login.google.connecting": "جارٍ الاتصال…", - "login.google.errorGeneric": "حدث خطأ في تسجيل الدخول عبر Google.", - "login.google.errorFailed": "فشل تسجيل الدخول عبر Google. حاول مرة أخرى.", - "landing.nav.why": "لماذا نحن؟", - "landing.nav.formats": "التنسيقات", - "landing.nav.pricing": "الأسعار", - "landing.nav.login": "تسجيل الدخول", - "landing.nav.startFree": "ابدأ مجانًا", - "landing.hero.tag": "ذكاء اصطناعي احترافي للمستندات", - "landing.hero.titleLine1": "ترجم مستنداتك.", - "landing.hero.titleLine2": "مع تنسيق مثالي.", - "landing.hero.description": "المترجم الوحيد الذي يحافظ على SmartArt والرسوم البيانية وجداول المحتويات والأشكال والتخطيطات المعقدة — تمامًا كما كانت.", - "landing.hero.ctaMain": "ابدأ مجانًا — مستندان/شهر", - "landing.hero.ctaSec": "عرض العروض", - "landing.hero.deleted": "الملفات تُحذف بعد 60 دقيقة", - "landing.hero.noHidden": "بدون رسوم خفية", - "landing.hero.preview": "معاينة قبل الدفع", - "landing.hero.formattedOk": "التنسيق سليم", - "landing.hero.aiActive": "ترجمة الذكاء الاصطناعي نشطة", - "landing.steps.title": "كيف يعمل؟", - "landing.steps.subtitle": "ثلاث خطوات. صفر فقدان في التنسيق.", - "landing.steps.step1.num": "01", - "landing.steps.step1.title": "ارفع ملفك", - "landing.steps.step1.desc": "اسحب وأفلت مستند Excel أو Word أو PowerPoint أو PDF.", - "landing.steps.step2.num": "02", - "landing.steps.step2.title": "اختر اللغة والمحرك", - "landing.steps.step2.desc": "حدد اللغة المستهدفة والمحرك — كلاسيكي أو ذكاء اصطناعي سياقي.", - "landing.steps.step3.num": "03", - "landing.steps.step3.title": "حمّل النتيجة", - "landing.steps.step3.desc": "احصل على مستندك المترجم بتنسيق مطابق تمامًا للأصل.", - "landing.features.tag": "محرك ترجمة بالذكاء الاصطناعي", - "landing.features.title": "ترجمة تفهم مجالك", - "landing.features.description": "نماذج الذكاء الاصطناعي لدينا تحلل السياق وتحترم مصطلحاتك وحتى تترجم النصوص داخل الصور.", - "landing.features.context.title": "سياق الصناعة", - "landing.features.context.desc": "صِف مجالك واحصل على ترجمات مخصصة، وليس عامة.", - "landing.features.glossary.title": "قواميس المصطلحات", - "landing.features.glossary.desc": "حدد مصطلحاتك التقنية. CTA تبقى «وحدة معالجة الهواء»، وليس «الدعوة للإجراء».", - "landing.features.vision.title": "التعرف على الصور", - "landing.features.vision.desc": "النص المضمن في الصور والمخططات والرسوم البياني يتم اكتشافه وترجمته.", - "landing.features.demo.source": "المصدر (FR)", - "landing.features.demo.google": "Google Translate", - "landing.features.demo.ours": "ذكاؤنا الاصطناعي", - "landing.layout.title": "تنسيقك،", - "landing.layout.title2": "محفوظ بشكل مثالي", - "landing.layout.subtitle": "المترجمون الآخرون يدمرون تخطيطك. نحن لا.", - "landing.layout.p1.title": "SmartArt والمخططات", - "landing.layout.p1.desc": "الهياكل التنظيمية، المخططات الانسيابية، التسلسلات الهرمية — كلها مترجمة بشكل مطابق.", - "landing.layout.p2.title": "جداول المحتويات", - "landing.layout.p2.desc": "إدخالات جدول المحتويات وأرقام الصفحات والمراجع المتبادلة محدثة بشكل صحيح.", - "landing.layout.p3.title": "الرسوم والمخططات البيانية", - "landing.layout.p3.desc": "العناوين، تسميات المحاور، التسميات التوضيحية وأسماء السلاسل — كل شيء مترجم.", - "landing.layout.p4.title": "الأشكال ومربعات النص", - "landing.layout.p4.desc": "مستطيلات، كتل مستديرة، تعليقات توضيحية — محلية في كل مكان.", - "landing.layout.p5.title": "الرؤوس والتذييلات", - "landing.layout.p5.desc": "الرؤوس والتذييلات والحواشي لا تُفوت أبدًا.", - "landing.layout.p6.title": "130+ لغة", - "landing.layout.p6.desc": "Google Translate و DeepL ومحركات ذكاء اصطناعي احترافية.", - "landing.formats.title": "كل تنسيق،", - "landing.formats.title2": "كل عنصر", - "landing.formats.subtitle": "نترجم ما يفوته الآخرون. عملك يستحق توثيقًا لا تشوبه شائبة.", - "landing.formats.word.name": "Word", - "landing.formats.word.i1": "الفقرات والعناوين", - "landing.formats.word.i2": "الجداول والرسوم البيانية", - "landing.formats.word.i3": "مخططات SmartArt", - "landing.formats.word.i4": "جدول المحتويات", - "landing.formats.word.i5": "الرؤوس والتذييلات", - "landing.formats.word.i6": "الأشكال ومربعات النص", - "landing.formats.word.i7": "الحواشي والتعليقات الختامية", - "landing.formats.excel.name": "Excel", - "landing.formats.excel.i1": "قيم الخلايا", - "landing.formats.excel.i2": "أسماء الأوراق", - "landing.formats.excel.i3": "الرسوم والتسميات", - "landing.formats.excel.i4": "الرؤوس والتذييلات", - "landing.formats.excel.i5": "الخلايا المدمجة محفوظة", - "landing.formats.pptx.name": "PowerPoint", - "landing.formats.pptx.i1": "نص الشرائح والملاحظات", - "landing.formats.pptx.i2": "الرسوم والمخططات", - "landing.formats.pptx.i3": "الأشكال ومربعات النص", - "landing.formats.pptx.i4": "التخطيطات الرئيسية", - "landing.formats.pptx.i5": "الرسوم المتحركة محفوظة", - "landing.formats.pdf.name": "PDF", - "landing.formats.pdf.i1": "ملفات PDF النصية", - "landing.formats.pdf.i2": "التخطيط محفوظ", - "landing.formats.pdf.i3": "الصور في مكانها", - "landing.formats.pdf.i4": "الجداول محفوظة", - "landing.formats.pdf.i5": "الإخراج كـ DOCX أو PDF", - "landing.pricing.title": "أسعار بسيطة وشفافة", - "landing.pricing.subtitle": "ما تراه هو ما تدفعه. بدون رسوم خفية.", - "landing.pricing.monthly": "شهريًا", - "landing.pricing.annual": "سنويًا", - "landing.pricing.bestValue": "الأكثر شعبية", - "landing.pricing.month": "/شهر", - "landing.pricing.footer": "السعر المعروض هو السعر الذي تدفعه. بدون رسوم خفية بعد الترجمة.", - "landing.pricing.starter.name": "Starter", - "landing.pricing.starter.desc": "للأفراد والمشاريع الصغيرة", - "landing.pricing.starter.f1": "50 مستند / شهر", - "landing.pricing.starter.f2": "حتى 50 صفحة لكل مستند", - "landing.pricing.starter.f3": "Google Translate + DeepL", - "landing.pricing.starter.f4": "ملفات حتى 10 ميجابايت", - "landing.pricing.starter.cta": "ابدأ الآن", - "landing.pricing.pro.name": "Pro", - "landing.pricing.pro.desc": "للمحترفين المتميزين", - "landing.pricing.pro.f1": "200 مستند / شهر", - "landing.pricing.pro.f2": "حتى 200 صفحة لكل مستند", - "landing.pricing.pro.f3": "ترجمة بالذكاء الاصطناعي", - "landing.pricing.pro.f4": "Google + DeepL مشمولان", - "landing.pricing.pro.f5": "قواميس وأوامر مخصصة", - "landing.pricing.pro.f6": "دعم ذو أولوية", - "landing.pricing.pro.cta": "جرّب Pro", - "landing.pricing.business.name": "الأعمال", - "landing.pricing.business.desc": "للفرق ذات الاحتياجات الكبيرة", - "landing.pricing.business.f1": "1,000 مستند / شهر", - "landing.pricing.business.f2": "حتى 500 صفحة لكل مستند", - "landing.pricing.business.f3": "ذكاء اصطناعي متميز (Claude)", - "landing.pricing.business.f4": "جميع المزودين + واجهة برمجة التطبيقات", - "landing.pricing.business.f5": "خطاطف الويب والأتمتة", - "landing.pricing.business.f6": "5 مقاعد للفريق", - "landing.pricing.business.cta": "تواصل معنا", - "landing.cta.title": "ابدأ الترجمة في 30 ثانية", - "landing.cta.subtitle": "لا حاجة لبطاقة ائتمان. جرّب مجانًا الآن وأعد الحياة إلى مستنداتك متعددة اللغات.", - "landing.cta.button": "إنشاء حساب مجاني", - "landing.cta.secure": "محمي بتشفير AES-256", - "landing.footer.desc": "خبراء في الترجمة الذكية للمستندات. نمزج بين فن التنسيق وعلم الذكاء الاصطناعي السياقي.", - "landing.footer.product": "المنتج", - "landing.footer.resources": "الموارد", - "landing.footer.legal": "قانوني", - "landing.footer.rights": "© 2026 Wordly.art — جميع الحقوق محفوظة.", - "dashboard.translate.pageTitle": "ترجمة مستند", - "dashboard.translate.pageSubtitle": "استورد ملفًا واختر اللغة الهدف", - "dashboard.translate.errorNotificationTitle": "خطأ", - "dashboard.translate.dropzone.uploadAria": "منطقة إسقاط الملفات", - "dashboard.translate.dropzone.title": "اسحب ملفك وأفلته هنا", - "dashboard.translate.dropzone.subtitle": "أو انقر للاختيار (DOCX, XLSX, PPTX, PDF)", - "dashboard.translate.dropzone.replaceFile": "استبدال الملف", - "dashboard.translate.language.source": "لغة المصدر", - "dashboard.translate.language.target": "اللغة الهدف", - "dashboard.translate.language.loading": "جارٍ تحميل اللغات…", - "dashboard.translate.language.autoDetect": "كشف تلقائي", - "dashboard.translate.language.selectPlaceholder": "اختيار…", - "dashboard.translate.language.loadErrorPrefix": "فشل تحميل اللغات", - "dashboard.translate.provider.loading": "جارٍ تحميل مزوّدي الخدمة…", - "dashboard.translate.provider.noneConfigured": "لا يوجد مزوّدو خدمة مُعدّون", - "dashboard.translate.provider.modelTitle": "النموذج", - "dashboard.translate.provider.sectionTitle": "مزوّد الخدمة", - "dashboard.translate.provider.llmDivider": "ذكاء اصطناعي · مدرك للسياق", - "dashboard.translate.provider.llmDividerPro": "ذكاء اصطناعي · مدرك للسياق (Pro)", - "dashboard.translate.provider.upgrade": "الترقية إلى Pro", - "dashboard.translate.provider.upgradeSuffix": "لفتح ترجمة الذكاء الاصطناعي", - "dashboard.translate.trust.zeroRetention": "صفر احتفاظ بالبيانات", - "dashboard.translate.trust.deletedAfter": "تُحذف الملفات بعد المعالجة", - "dashboard.translate.actions.uploading": "جارٍ الرفع…", - "dashboard.translate.actions.translate": "ترجمة", - "dashboard.translate.actions.filePrefix": "الملف: ", - "dashboard.translate.actions.cancel": "إلغاء", - "dashboard.translate.actions.tryAgain": "إعادة المحاولة", - "dashboard.translate.steps.uploading": "جارٍ رفع الملف…", - "dashboard.translate.steps.starting": "جارٍ بدء الترجمة…", - "dashboard.translate.complete.title": "تمت الترجمة بنجاح!", - "dashboard.translate.complete.descNamed": "تمت ترجمة ملفك {name} بنجاح.", - "dashboard.translate.complete.descGeneric": "تمت ترجمة ملفك بنجاح.", - "dashboard.translate.complete.downloading": "جارٍ التنزيل…", - "dashboard.translate.complete.download": "تنزيل", - "dashboard.translate.complete.newTranslation": "ترجمة جديدة", - "dashboard.translate.complete.toastOkTitle": "تم بنجاح", - "dashboard.translate.complete.toastOkDesc": "تم تنزيل {name} بنجاح.", - "dashboard.translate.complete.toastFailTitle": "فشل", - "dashboard.translate.complete.toastFailDesc": "فشلت الترجمة. يرجى إعادة المحاولة.", - "dashboard.translate.sourceDocument": "المستند المصدر", - "dashboard.translate.configuration": "الإعدادات", - "dashboard.translate.translating": "جارٍ الترجمة", - "dashboard.translate.liveMonitor": "المراقبة المباشرة", - "dashboard.translate.summary": "الملخص", - "dashboard.translate.engine": "المحرك", - "dashboard.translate.confidence": "الثقة", - "dashboard.translate.cancel": "إلغاء", - "dashboard.translate.segments": "الأجزاء", - "dashboard.translate.characters": "الأحرف", - "dashboard.translate.elapsed": "المنقضي", - "dashboard.translate.segPerMin": "جزء/دقيقة", - "dashboard.translate.highQuality": "جودة عالية", - "dashboard.translate.quality": "الجودة", - "dashboard.translate.completed": "اكتملت الترجمة", - "dashboard.translate.replace": "استبدال", - "dashboard.translate.pdfMode.title": "وضع ترجمة PDF", - "dashboard.translate.pdfMode.preserveLayout": "الحفاظ على التخطيط", - "dashboard.translate.pdfMode.textOnly": "نص فقط", - "dashboard.translate.pdfMode.preserveLayoutDesc": "يحافظ على الصور والجداول والتنسيق. مثالي لملفات PDF البسيطة.", - "dashboard.translate.pdfMode.textOnlyDesc": "يترجم كل النص بشكل مثالي. مخرجات نظيفة دون مشاكل تخطيط.", - "dashboard.translate.pipeline.upload": "رفع", - "dashboard.translate.pipeline.analyze": "تحليل", - "dashboard.translate.pipeline.translate": "ترجمة", - "dashboard.translate.pipeline.rebuild": "إعادة بناء", - "dashboard.translate.pipeline.finalize": "إنهاء", - "dashboard.translate.progress.processingFallback": "جارٍ المعالجة…", - "dashboard.translate.progress.connectionLost": "فُقد الاتصال. إعادة المحاولة…", - "dashboard.translate.progress.failedTitle": "فشلت الترجمة", - "dashboard.translate.error.unexpected": "حدث خطأ غير متوقع. يرجى المحاولة مرة أخرى.", - "dashboard.translate.error.noResult": "لم تُنتج الترجمة أي نتائج. تحقق من أن المستند يحتوي على نص، ثم أعد المحاولة أو اختر محركًا آخر.", - "dashboard.translate.error.apiKey": "مفتاح API غير صالح أو مفقود. اتصل بالمسؤول لإعداد مفاتيح API.", - "dashboard.translate.error.quota": "تم بلوغ حد الاستخدام. أعد المحاولة بعد بضع دقائق أو اختر محركًا آخر.", - "dashboard.translate.error.timeout": "انتهت مهلة الاتصال بخدمة الترجمة. تحقق من شبكتك وأعد المحاولة.", - "dashboard.translate.error.sessionExpired": "انتهت الجلسة. انقر على إعادة المحاولة لإعادة تشغيل الترجمة.", - "dashboard.translate.error.empty": "يبدو أن المستند فارغ أو لا يحتوي على نص قابل للترجمة (صورة PDF ممسوحة ضوئيًا؟).", - "dashboard.translate.error.unsupported": "تنسيق ملف غير مدعوم أو ملف تالف.", - "dashboard.translate.error.connection": "فُقد الاتصال. تحقق من شبكتك وأعد المحاولة.", - "dashboard.translate.error.generic": "فشلت الترجمة: {detail}", - "dashboard.translate.error.title": "فشلت الترجمة", - "dashboard.translate.retry": "إعادة محاولة الترجمة", - "dashboard.translate.newFile": "ملف جديد", - "dashboard.translate.modeAI": "وضع الذكاء الاصطناعي", - "dashboard.translate.modeClassic": "الوضع الكلاسيكي", - "dashboard.translate.glossaryLLMHint": "القواميس المصطلحية متاحة في وضع الذكاء الاصطناعي", - "dashboard.translate.submitting": "جارٍ الإرسال...", - "dashboard.translate.submit": "بدء الترجمة", - "dashboard.translate.noFile": "قم بتحميل ملف أولاً", - "dashboard.translate.noTargetLang": "اختر لغة الهدف", - "glossaries.yourGlossaries": "معاجمك", - "glossaries.title": "المعاجم والسياق", - "glossaries.description": "قم بإدارة معاجمك وتعليمات السياق للحصول على ترجمات أكثر دقة.", - "glossaries.createNew": "إنشاء جديد", - "glossaries.empty": "لا توجد معاجم بعد", - "glossaries.emptyDesc": "أنشئ أول معجم لك أو حمّل إعدادًا مسبقًا احترافيًا أعلاه", - "glossaries.defineTerms": "مصطلحات", - "glossaries.aboutTitle": "حول المعاجم", - "glossaries.aboutDesc": "تتيح لك المعاجم تحديد ترجمات دقيقة لمصطلحات معينة. عند الترجمة، يتم استخدام مصطلحات المعجم لضمان ترجمات متسقة ودقيقة.", - "glossaries.aboutFormat": "كل مصطلح له كلمة مصدر وترجمات بلغات متعددة. حدد معجمًا في صفحة الترجمة لتطبيقه.", - "glossaries.toast.created": "تم إنشاء المعجم", - "glossaries.toast.createdDesc": "تم إنشاء المعجم \"{name}\".", - "glossaries.toast.imported": "تم استيراد المعجم", - "glossaries.toast.importedDesc": "تم استيراد المعجم \"{name}\".", - "glossaries.toast.updated": "تم تحديث المعجم", - "glossaries.toast.updatedDesc": "تم تحديث المعجم \"{name}\".", - "glossaries.toast.deleted": "تم حذف المعجم", - "glossaries.toast.deletedDesc": "تم حذف المعجم.", - "glossaries.toast.error": "خطأ", - "glossaries.toast.errorCreate": "فشل إنشاء المعجم", - "glossaries.toast.errorImport": "فشل استيراد المعجم", - "glossaries.toast.errorUpdate": "فشل تحديث المعجم", - "glossaries.toast.errorDelete": "فشل حذف المعجم", - "glossaries.dialog.title": "معجم جديد", - "glossaries.dialog.description": "أنشئ معجمًا لترجماتك", - "glossaries.dialog.nameLabel": "الاسم", - "glossaries.dialog.namePlaceholder": "معجمي", - "glossaries.dialog.tabTemplates": "القوالب", - "glossaries.dialog.tabFile": "ملف", - "glossaries.dialog.tabManual": "يدوي", - "glossaries.dialog.cancel": "إلغاء", - "glossaries.dialog.creating": "جارٍ الإنشاء…", - "glossaries.dialog.importing": "جارٍ الاستيراد…", - "glossaries.dialog.importBtn": "استيراد", - "glossaries.dialog.selectPrompt": "اختيار", - "glossaries.dialog.createBtn": "إنشاء", - "glossaries.dialog.createEmpty": "إنشاء فارغ", - "glossaries.dialog.terms": "مصطلحات", - "glossaries.dialog.templatesDesc": "اختر قالبًا مُعدًّا مسبقًا", - "glossaries.dialog.templatesEmpty": "لا توجد قوالب متاحة", - "glossaries.dialog.dropTitle": "اسحب ملف CSV هنا", - "glossaries.dialog.dropOr": "أو", - "glossaries.dialog.dropFormats": "CSV, TSV, TXT", - "glossaries.termEditor.addTerm": "إضافة مصطلح", - "glossaries.termEditor.maxReached": "تم بلوغ الحد الأقصى {max} من المصطلحات لكل قاموس.", - "glossaries.dialog.formatTitle": "التنسيق", - "glossaries.dialog.formatDesc": "المصدر،الهدف (واحدة لكل سطر)", - "glossaries.dialog.formatNote": "يُتجاهل السطر الأول عند اكتشاف ترويسة", - "glossaries.dialog.errorFormat": "تنسيق غير مدعوم", - "glossaries.dialog.errorSize": "الملف كبير جدًا", - "glossaries.dialog.errorEmpty": "ملف فارغ", - "glossaries.dialog.errorRead": "خطأ في القراءة", - "glossaries.dialog.parsing": "جارٍ التحليل…", - "glossaries.dialog.termsImported": "مصطلحات مستوردة", - "glossaries.dialog.changeFile": "تغيير الملف", - "glossaries.dialog.retry": "إعادة المحاولة", - "glossaries.edit.title": "Modifier le glossaire", - "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", - "glossaries.edit.nameLabel": "Nom du glossaire", - "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", - "glossaries.edit.sourceLang": "Langue source", - "glossaries.edit.targetLang": "Langue cible", - "glossaries.edit.termsLabel": "Termes ({count} valides)", - "glossaries.edit.exportCsv": "Exporter CSV", - "glossaries.edit.importCsv": "Importer CSV", - "glossaries.edit.cancel": "Annuler", - "glossaries.edit.saving": "Enregistrement...", - "glossaries.edit.saveChanges": "Enregistrer les modifications", - "glossaries.edit.importFailedTitle": "Échec de l'importation", - "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", - "glossaries.edit.importSuccessTitle": "Importation réussie", - "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", - "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", - "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", - "glossaries.delete.title": "Supprimer le glossaire", - "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", - "glossaries.delete.warning": "Cette action est irréversible", - "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", - "glossaries.delete.cancel": "Annuler", - "glossaries.delete.deleting": "Suppression...", - "glossaries.delete.deleteBtn": "Supprimer", - "glossaries.upgrade.title": "Glossaires", - "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", - "glossaries.upgrade.feature1": "Créez plusieurs glossaires", - "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", - "glossaries.upgrade.feature3": "Importez/exportez via CSV", - "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", - "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", - "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", - "glossaries.upgrade.proLabel": "Pro", - "glossaries.upgrade.upgradeBtn": "Passer à Pro", - "glossaries.loading": "Chargement...", - "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", - "glossaries.howItWorks.step1Title": "Configurez ici", - "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", - "glossaries.howItWorks.step2Title": "Activez dans Traduire", - "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", - "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", - "glossaries.howItWorks.goToTranslate": "Aller à Traduire", - "glossaries.status.unsaved": "Non enregistré", - "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", - "glossaries.status.inactive": "Inactif", - "glossaries.instructions.whatForBold": "À quoi ça sert ?", - "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", - "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", - "glossaries.instructions.charCount": "{count} caractères", - "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", - "glossaries.instructions.clearAll": "Tout effacer", - "glossaries.instructions.saving": "Enregistrement…", - "glossaries.instructions.saved": "Enregistré", - "glossaries.presets.whatForBold": "À quoi ça sert ?", - "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", - "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", - "glossaries.presets.creating": "Création…", - "glossaries.presets.alreadyImported": "Déjà importé", - "glossaries.presets.it.title": "IT / Logiciel", - "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", - "glossaries.presets.legal.title": "Juridique / Contrats", - "glossaries.presets.legal.desc": "Droit des affaires, contentieux", - "glossaries.presets.medical.title": "Médical / Santé", - "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", - "glossaries.presets.finance.title": "Finance / Comptabilité", - "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", - "glossaries.presets.marketing.title": "Marketing / Publicité", - "glossaries.presets.marketing.desc": "Digital, branding, analytics", - "glossaries.presets.hr.title": "RH / Ressources Humaines", - "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", - "glossaries.presets.scientific.title": "Scientifique / Recherche", - "glossaries.presets.scientific.desc": "Publications, thèses, articles", - "glossaries.presets.ecommerce.title": "E-commerce / Vente", - "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", - "glossaries.grid.title": "Vos", - "glossaries.grid.titleHighlight": "glossaires", - "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", - "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", - "glossaries.grid.activeTranslation": "Traduction active :", - "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", - "glossaries.badge.compatible": "Compatible", - "glossaries.badge.otherTarget": "Autre cible", - "glossaries.card.editTerms": "Modifier les termes", - "glossaries.card.created": "تم الإنشاء", - "glossaries.card.term": "مصطلح", - "glossaries.card.delete": "Supprimer", - "glossaries.grid.searchPlaceholder": "Search a glossary…", - "glossaries.grid.noResults": "No results for this search.", - "glossaries.detail.backToList": "Back to glossaries", - "glossaries.detail.save": "Save", - "glossaries.detail.savedTitle": "Saved", - "glossaries.detail.savedDesc": "The glossary has been updated.", - "glossaries.detail.settingsTitle": "Settings", - "glossaries.detail.sourceLang": "Source language", - "glossaries.detail.targetLang": "Target language", - "glossaries.detail.termsTitle": "Terms", - "glossaries.detail.terms": "terms", - "glossaries.detail.searchTerms": "Filter…", - "glossaries.detail.noTerms": "No terms yet.", - "glossaries.detail.addFirstTerm": "Add the first term", - "glossaries.detail.addTerm": "Add a term", - "glossaries.detail.maxReached": "Maximum limit reached", - "glossaries.detail.source": "Source", - "glossaries.detail.target": "Target", - "glossaries.detail.sourcePlaceholder": "source term", - "glossaries.detail.targetPlaceholder": "target term", - "glossaries.detail.csvTitle": "CSV", - "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", - "glossaries.detail.export": "Export", - "glossaries.detail.import": "Import", - "glossaries.detail.dangerTitle": "Danger zone", - "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", - "glossaries.detail.deleteGlossary": "Delete this glossary", - "glossaries.detail.confirmDelete": "Confirm deletion?", - "glossaries.detail.confirm": "Confirm", - "glossaries.detail.cancel": "Cancel", - "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", - "glossaries.detail.sourceLocked": "fixed", - "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", - "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", - "glossaries.detail.notFoundTitle": "Glossary not found", - "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", - "glossaries.detail.maxTermsTitle": "Limit reached", - "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", - "glossaries.detail.importEmptyTitle": "Empty file", - "glossaries.detail.importEmptyDesc": "No terms detected in this file.", - "glossaries.detail.importedTitle": "Imported", - "glossaries.detail.importedDesc": "{count} terms imported.", - "glossaries.detail.importErrorTitle": "Read error", - "glossaries.detail.importErrorDesc": "Unable to read the file.", - "apiKeys.webhook.title": "Intégration Webhook", - "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", - "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", - "apiKeys.webhook.codeParam": "webhook_url", - "translate.mode.label": "Mode de traduction", - "translate.mode.classic": "Classique", - "translate.mode.classicDesc": "Rapide", - "translate.mode.proLlm": "Pro LLM", - "translate.mode.proLlmDesc": "Contextuel", - "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", - "translate.mode.upgradeLink": "Passer à Pro", - "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", - "pricing.nav.back": "رجوع", - "pricing.nav.home": "الرئيسية", - "pricing.nav.mySubscription": "اشتراكي", - "pricing.header.badge": "نماذج الذكاء الاصطناعي المحدّثة — مارس 2026", - "pricing.header.title": "خطة لكل احتياج", - "pricing.header.subtitle": "ترجم مستندات Word و Excel و PowerPoint مع الحفاظ على التنسيق الأصلي. بدون الحاجة إلى مفتاح API.", - "pricing.billing.monthly": "شهري", - "pricing.billing.yearly": "سنوي", - "pricing.plans.free.name": "مجاني", - "pricing.plans.starter.name": "Starter", - "pricing.plans.pro.name": "Pro", - "pricing.plans.business.name": "Business", - "pricing.plans.enterprise.name": "Enterprise", - "pricing.plans.free.description": "مثالي لاكتشاف التطبيق", - "pricing.plans.starter.description": "للأفراد والمشاريع الصغيرة", - "pricing.plans.pro.description": "للمحترفين والفرق النامية", - "pricing.plans.business.description": "للفرق والمؤسسات", - "pricing.plans.enterprise.description": "حلول مخصصة للمؤسسات الكبيرة", - "pricing.plans.pro.highlight": "الأكثر شعبية", - "pricing.plans.pro.badge": "رائج", - "pricing.plans.enterprise.badge": "حسب الطلب", - "pricing.plans.free.feat1": "5 مستندات / شهر", - "pricing.plans.free.feat2": "حتى 15 صفحة لكل مستند", - "pricing.plans.free.feat3": "ترجمة Google مشمولة", - "pricing.plans.free.feat4": "جميع اللغات (130+)", - "pricing.plans.free.feat5": "دعم المجتمع", - "pricing.plans.starter.feat1": "50 مستندًا / شهر", - "pricing.plans.starter.feat2": "حتى 50 صفحة لكل مستند", - "pricing.plans.starter.feat3": "ترجمة Google + DeepL", - "pricing.plans.starter.feat4": "ملفات حتى 10 ميغابايت", - "pricing.plans.starter.feat5": "دعم عبر البريد الإلكتروني", - "pricing.plans.starter.feat6": "سجل 30 يومًا", - "pricing.plans.pro.feat1": "200 مستند / شهر", - "pricing.plans.pro.feat2": "حتى 200 صفحة لكل مستند", - "pricing.plans.pro.feat3": "ترجمة الذكاء الاصطناعي الأساسية", - "pricing.plans.pro.feat4": "ترجمة Google + DeepL", - "pricing.plans.pro.feat5": "ملفات حتى 25 ميغابايت", - "pricing.plans.pro.feat6": "معاجم مخصصة", - "pricing.plans.pro.feat7": "دعم ذو أولوية", - "pricing.plans.pro.feat8": "سجل 90 يومًا", - "pricing.plans.business.feat1": "1 000 مستند / شهر", - "pricing.plans.business.feat2": "حتى 500 صفحة لكل مستند", - "pricing.plans.business.feat3": "AI أساسية + متميزة (Claude Haiku)", - "pricing.plans.business.feat4": "جميع مزوّدي الترجمة", - "pricing.plans.business.feat5": "ملفات حتى 50 ميغابايت", - "pricing.plans.business.feat6": "وصول API (10 000 استدعاء/شهر)", - "pricing.plans.business.feat7": "ويب هوك للإشعارات", - "pricing.plans.business.feat8": "دعم مخصص", - "pricing.plans.business.feat9": "سجل سنة واحدة", - "pricing.plans.business.feat10": "تحليلات متقدمة", - "pricing.plans.enterprise.feat1": "مستندات بلا حدود", - "pricing.plans.enterprise.feat2": "جميع نماذج AI (GPT-5, Claude Opus 4.6…)", - "pricing.plans.enterprise.feat3": "نشر محلي أو سحابة مخصصة", - "pricing.plans.enterprise.feat4": "SLA 99.9% مضمون", - "pricing.plans.enterprise.feat5": "دعم مخصص على مدار الساعة", - "pricing.plans.enterprise.feat6": "العلامة البيضاء (White-label)", - "pricing.plans.enterprise.feat7": "فرق بلا حدود", - "pricing.plans.enterprise.feat8": "تكاملات مخصصة", - "pricing.card.onRequest": "حسب الطلب", - "pricing.card.free": "مجاني", - "pricing.card.perMonth": "/شهر", - "pricing.card.billedYearly": "يُحاسب {price} € / سنة", - "pricing.card.documents": "المستندات", - "pricing.card.pagesMax": "الحد الأقصى للصفحات", - "pricing.card.aiTranslation": "ترجمة AI", - "pricing.card.unlimited": "بلا حدود", - "pricing.card.perMonthStat": "/ شهر", - "pricing.card.perDoc": "ص / مستند", - "pricing.card.aiEssential": "أساسي", - "pricing.card.aiEssentialPremium": "أساسي + متميز", - "pricing.card.aiCustom": "مخصص", - "pricing.card.myPlan": "خطتي", - "pricing.card.managePlan": "إدارة خطتي", - "pricing.card.startFree": "ابدأ مجانًا", - "pricing.card.contactUs": "تواصل معنا", - "pricing.card.choosePlan": "اختر هذه الخطة", - "pricing.card.processing": "جارٍ المعالجة…", - "pricing.comparison.title": "مقارنة تفصيلية", - "pricing.comparison.subtitle": "كل ما هو مشمول في كل خطة", - "pricing.comparison.feature": "الميزة", - "pricing.comparison.docsPerMonth": "المستندات / شهر", - "pricing.comparison.pagesMaxPerDoc": "الحد الأقصى للصفحات / مستند", - "pricing.comparison.maxFileSize": "الحد الأقصى لحجم الملف", - "pricing.comparison.googleTranslation": "ترجمة Google", - "pricing.comparison.deepl": "DeepL", - "pricing.comparison.aiEssential": "ترجمة AI أساسية", - "pricing.comparison.aiPremium": "ترجمة AI متميزة", - "pricing.comparison.apiAccess": "وصول API", - "pricing.comparison.priorityProcessing": "معالجة ذات أولوية", - "pricing.comparison.support": "الدعم", - "pricing.comparison.support.community": "المجتمع", - "pricing.comparison.support.email": "البريد الإلكتروني", - "pricing.comparison.support.priority": "ذو أولوية", - "pricing.comparison.support.dedicated": "مخصص", - "pricing.comparison.mb": "ميغابايت", - "pricing.credits.title": "أرصدة إضافية", - "pricing.credits.subtitle": "تحتاج المزيد؟ اشترِ أرصدة فردية بدون اشتراك.", - "pricing.credits.perPage": "رصيد واحد = صفحة واحدة مترجمة.", - "pricing.credits.bestValue": "أفضل قيمة", - "pricing.credits.unit": "أرصدة", - "pricing.credits.centsPerCredit": "سنت / رصيد", - "pricing.credits.buy": "شراء", - "pricing.trust.encryption.title": "تشفير شامل", - "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 في حالة السكون", - "pricing.trust.languages.title": "+130 لغة", - "pricing.trust.languages.sub": "بما فيها العربية والفارسية والعبرية (RTL)", - "pricing.trust.parallel.title": "معالجة متوازية", - "pricing.trust.parallel.sub": "ذكاء اصطناعي متعدد المسارات فائق السرعة", - "pricing.trust.availability.title": "متاح على مدار الساعة", - "pricing.trust.availability.sub": "ضمان وقت تشغيل 99.9%", - "pricing.aiModels.title": "نماذج الذكاء الاصطناعي — مارس 2026", - "pricing.aiModels.essential.title": "ترجمة AI أساسية", - "pricing.aiModels.essential.plan": "خطة Pro", - "pricing.aiModels.essential.descPrefix": "مبني على", - "pricing.aiModels.essential.descSuffix": "— أنموذج الذكاء الاصطناعي الأكثر فعالية من حيث التكلفة لعام 2026. جودة مماثلة للنماذج المتقدمة بتكلفة أقل بكثير.", - "pricing.aiModels.essential.modelName": "نموذج الذكاء الاصطناعي الأساسي", - "pricing.aiModels.essential.context": "163K رمز سياقي", - "pricing.aiModels.essential.value": "قيمة ممتازة مقابل المال", - "pricing.aiModels.premium.title": "ترجمة AI متميزة", - "pricing.aiModels.premium.plan": "خطة Business", - "pricing.aiModels.premium.descPrefix": "مبني على", - "pricing.aiModels.premium.descSuffix": "من Anthropic — دقة عالية في المستندات القانونية والطبية والتقنية المعقدة.", - "pricing.aiModels.premium.context": "200K رمز سياقي", - "pricing.aiModels.premium.precision": "أعلى دقة", - "pricing.faq.title": "الأسئلة الشائعة", - "pricing.faq.q1": "هل يمكنني تغيير خطتي في أي وقت؟", - "pricing.faq.a1": "نعم. الترقية فورية ومُحاسب عليها بالتناسب. التخفيض يسري في نهاية الفترة الحالية.", - "pricing.faq.q2": "ما هي «ترجمة AI الأساسية»؟", - "pricing.faq.a2": "إنه محرك الذكاء الاصطناعي الخاص بنا. يفهم سياق مستنداتك، ويحافظ على التخطيط، ويتعامل مع المصطلحات التقنية بشكل أفضل بكثير من الترجمة الكلاسيكية.", - "pricing.faq.q3": "ما الفرق بين AI الأساسية وAI المتميزة؟", - "pricing.faq.a3": "الذكاء الاصطناعي الأساسي يستخدم نموذجًا محسّنًا (قيمة ممتازة مقابل المال). الذكاء الاصطناعي المتميز يستخدم Claude 3.5 Haiku من Anthropic، أكثر دقة في المستندات القانونية والطبية والتقنية المعقدة.", - "pricing.faq.q4": "هل تُحفظ مستنداتي بعد الترجمة؟", - "pricing.faq.a4": "الملفات المترجمة متاحة حسب خطتك (30 يومًا لـ Starter، 90 يومًا لـ Pro، سنة واحدة لـ Business). وهي مشفرة أثناء التخزين والنقل.", - "pricing.faq.q5": "ماذا يحدث إذا تجاوزت حصتي الشهرية؟", - "pricing.faq.a5": "يمكنك شراء أرصدة إضافية بشكل فردي أو ترقية خطتك. يتم إشعارك عند بلوغ 80% من الاستخدام.", - "pricing.faq.q6": "هل توجد فترة تجريبية مجانية للخطط المدفوعة؟", - "pricing.faq.a6": "الخطة المجانية دائمة ولا تتطلب بطاقة ائتمان. للخطط Pro و Business تواصل معنا للحصول على تجربة 14 يومًا.", - "pricing.faq.q7": "ما تنسيقات الملفات المدعومة؟", - "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx), and soon PDF. All plans support the same formats.", - "pricing.cta.title": "مستعد للبدء؟", - "pricing.cta.subtitle": "ابدأ مجانًا بدون بطاقة ائتمان. رقِّق عندما تحتاج.", - "pricing.cta.createAccount": "إنشاء حساب مجاني", - "pricing.cta.login": "تسجيل الدخول", - "pricing.toast.demo": "الوضع التجريبي — Stripe لم يُعدّ بعد. في بيئة الإنتاج سيتم توجيهك إلى الدفع لتفعيل خطة {planId}.", - "pricing.toast.networkError": "خطأ في الشبكة. يرجى إعادة المحاولة.", - "pricing.toast.paymentError": "خطأ أثناء إنشاء الدفع.", - "register.title": "إنشاء حساب", - "register.subtitle": "ابدأ الترجمة مجانًا", - "register.error.failed": "فشل التسجيل", - "register.name.label": "الاسم", - "register.name.placeholder": "اسمك", - "register.name.error": "يجب أن يحتوي الاسم على حرفين على الأقل", - "register.email.label": "البريد الإلكتروني", - "register.email.placeholder": "you@example.com", - "register.email.error": "عنوان بريد إلكتروني غير صالح", - "register.password.label": "كلمة المرور", - "register.password.error": "يجب أن تتكون كلمة المرور من 8 أحرف على الأقل، مع حرف كبير وحرف صغير ورقم", - "register.password.show": "إظهار كلمة المرور", - "register.password.hide": "إخفاء كلمة المرور", - "register.password.strengthLabel": "القوة:", - "register.password.strength.weak": "ضعيفة", - "register.password.strength.medium": "متوسطة", - "register.password.strength.strong": "قوية", - "register.confirmPassword.label": "تأكيد كلمة المرور", - "register.confirmPassword.error": "كلمتا المرور غير متطابقتين", - "register.confirmPassword.show": "إظهار", - "register.confirmPassword.hide": "إخفاء", - "register.submit.creating": "جارٍ إنشاء الحساب...", - "register.submit.create": "إنشاء حسابي", - "register.hasAccount": "لديك حساب بالفعل؟", - "register.login": "تسجيل الدخول", - "register.terms.prefix": "بإنشاء حساب، فإنك تقبل", - "register.terms.link": "شروط الخدمة الخاصة بنا", - - "common.loading": "جارٍ التحميل...", - "profile.header.title": "ملفي الشخصي", - "profile.header.subtitle": "إدارة حسابك وتفضيلاتك.", - "profile.tabs.account": "الحساب", - "profile.tabs.subscription": "الاشتراك", - "profile.tabs.preferences": "التفضيلات", - "profile.account.user": "المستخدم", - "profile.account.memberSince": "عضو منذ", - "profile.plan.label": "الخطة", - "profile.plan.free": "Free", - "profile.plan.starter": "Starter", - "profile.plan.pro": "Pro", - "profile.plan.business": "Business", - "profile.plan.enterprise": "Enterprise", - "profile.plan.pricePerMonth": "{price} €/شهر", - "profile.subscription.canceling": "جارٍ الإلغاء", - "profile.subscription.active": "نشط", - "profile.subscription.unknown": "غير معروف", - "profile.subscription.accessUntil": "الوصول حتى", - "profile.subscription.renewalOn": "التجديد في", - "profile.subscription.upgradePlan": "الترقية إلى خطة مدفوعة", - "profile.subscription.changePlan": "تغيير الخطة", - "profile.subscription.manageBilling": "إدارة الفوترة", - "profile.subscription.billingUnavailable": "بوابة الفوترة غير متاحة.", - "profile.subscription.billingError": "خطأ في الوصول إلى بوابة الفوترة.", - "profile.subscription.cancelSuccess": "تم إلغاء الاشتراك. تحتفظ بالوصول حتى نهاية الفترة.", - "profile.subscription.cancelError": "حدث خطأ أثناء الإلغاء.", - "profile.subscription.networkError": "خطأ في الشبكة.", - "profile.usage.title": "الاستخدام هذا الشهر", - "profile.usage.resetOn": "إعادة التعيين في", - "profile.usage.documents": "المستندات", - "profile.usage.pages": "الصفحات", - "profile.usage.extraCredits": "رصيد إضافي", - "profile.usage.extraCreditsPlural": "أرصدة إضافية", - "profile.usage.quotaReached": "تم بلوغ الحصة", - "profile.usage.quotaReachedDesc": "قم بالترقية إلى خطة أعلى للمتابعة.", - "profile.usage.unlockMore": "احصل على المزيد من الترجمات مع خطة مدفوعة.", - "profile.usage.viewPlans": "عرض الخطط", - "profile.usage.includedInPlan": "مضمن في خطتك", - "profile.danger.title": "منطقة الخطر", - "profile.danger.description": "يتم تطبيق الإلغاء في نهاية الفترة الحالية. تحتفظ بالوصول حتى ذلك التاريخ.", - "profile.danger.confirm": "هل أنت متأكد؟ لا يمكن التراجع عن هذا الإجراء.", - "profile.danger.confirmCancel": "تأكيد الإلغاء", - "profile.danger.cancelSubscription": "إلغاء اشتراكي", - "profile.danger.keep": "لا، إبقاء", - "profile.prefs.interfaceLang": "لغة الواجهة", - "profile.prefs.interfaceLangDesc": "يتم اكتشاف اللغة تلقائيًا بناءً على متصفحك. يمكنك تغييرها يدويًا.", - "profile.prefs.defaultTargetLang": "اللغة الهدف الافتراضية", - "profile.prefs.selectLanguage": "اختر لغة", - "profile.prefs.defaultTargetLangDesc": "سيتم تحديد هذه اللغة مسبقًا لترجماتك.", - "profile.prefs.save": "حفظ", - "profile.prefs.theme": "المظهر", - "profile.prefs.themeDesc": "اختر مظهر الواجهة", - "profile.prefs.cache": "ذاكرة التخزين المؤقت", - "profile.prefs.cacheDesc": "مسح ذاكرة التخزين المؤقت المحلية قد يحل بعض مشاكل العرض.", - "profile.prefs.clearing": "جارٍ المسح...", - "profile.prefs.clearCache": "مسح ذاكرة التخزين المؤقت", - "settings.title": "الإعدادات", - "settings.subtitle": "إعدادات التطبيق العامة", - "settings.formats.title": "التنسيقات المدعومة", - "settings.formats.subtitle": "أنواع المستندات التي يمكنك ترجمتها", - "settings.formats.formulas": "الصيغ", - "settings.formats.styles": "الأنماط", - "settings.formats.images": "الصور", - "settings.formats.headers": "الرؤوس", - "settings.formats.tables": "الجداول", - "settings.formats.slides": "الشرائح", - "settings.formats.notes": "الملاحظات", - "settings.cache.title": "ذاكرة التخزين المؤقت", - "settings.cache.desc": "مسح ذاكرة التخزين المؤقت المحلية قد يحل بعض مشاكل العرض.", - "settings.cache.clearing": "جارٍ المسح...", - "settings.cache.clear": "مسح ذاكرة التخزين المؤقت", - "services.title": "مزودو الترجمة", - "services.subtitle": "تم تكوين المزودين من قبل المسؤول. يمكنك معرفة أيهم متاح حاليًا لحسابك.", - "services.loading": "جارٍ تحميل المزودين...", - "services.noProviders": "لا يوجد مزودون مكوّنون حاليًا. اتصل بالمسؤول.", - "services.classic": "ترجمة كلاسيكية", - "services.llmPro": "LLM · مدرك للسياق (Pro)", - "services.available": "متاح", - "services.model": "النموذج", - "services.adminOnly.title": "تكوين المزودين للمسؤولين فقط", - "services.adminOnly.desc": "يتم إدارة مفاتيح API واختيار النماذج وتفعيل المزودين حصريًا من قبل المسؤول في لوحة الإدارة. لا تحتاج أبدًا إلى إدخال مفتاح API.", - "apiKeys.title": "مفاتيح API", - "apiKeys.subtitle": "إدارة مفاتيح API للوصول البرمجي إلى واجهة الترجمة.", - "apiKeys.loading": "جارٍ التحميل...", - "apiKeys.sectionTitle": "API والأتمتة", - "apiKeys.sectionDesc": "إنشاء وإدارة مفاتيح API لسير عمل الأتمتة", - "apiKeys.keysUsed": "{total} من {max} مفاتيح مستخدمة", - "apiKeys.maxReached": "تم بلوغ الحد الأقصى للمفاتيح. قم بإلغاء مفتاح لإنشاء واحد جديد.", - "apiKeys.canGenerate": "يمكنك إنشاء {count} مفتاح إضافي", - "apiKeys.canGeneratePlural": "يمكنك إنشاء {count} مفاتيح إضافية", - "apiKeys.generateNew": "إنشاء مفتاح جديد", - "apiKeys.keyRevoked": "تم إلغاء المفتاح", - "apiKeys.keyRevokedDesc": "تم إلغاء مفتاح API بنجاح.", - "apiKeys.keyNotFound": "المفتاح غير موجود", - "apiKeys.keyNotFoundDesc": "مفتاح API لم يعد موجودًا. ربما تم إلغاؤه بالفعل.", - "apiKeys.error": "خطأ", - "apiKeys.revokeError": "فشل إلغاء مفتاح API. يرجى المحاولة مرة أخرى.", - "apiKeys.limitReached": "تم بلوغ الحد", - "apiKeys.limitReachedDesc": "لقد وصلت إلى الحد الأقصى وهو 10 مفاتيح API. قم بإلغاء مفتاح حالي لإنشاء واحد جديد.", - "apiKeys.proRequired": "ميزة Pro مطلوبة", - "apiKeys.proRequiredDesc": "مفاتيح API هي ميزة Pro. يرجى ترقية حسابك.", - "apiKeys.generateError": "فشل إنشاء مفتاح API. يرجى المحاولة مرة أخرى.", - "apiKeys.upgrade.title": "مفاتيح API", - "apiKeys.upgrade.subtitle": "أتمتة ترجماتك مع وصول API", - "apiKeys.upgrade.feat1": "إنشاء مفاتيح API غير محدودة", - "apiKeys.upgrade.feat2": "أتمتة ترجمة المستندات", - "apiKeys.upgrade.feat3": "إشعارات Webhook", - "apiKeys.upgrade.feat4": "أوضاع ترجمة LLM", - "apiKeys.upgrade.proFeature": "مفاتيح API هي ميزة {pro}. قم بالترقية لفتح أتمتة API.", - "apiKeys.upgrade.pro": "Pro", - "apiKeys.upgrade.cta": "الترقية إلى Pro", - "apiKeys.dialog.maxTitle": "تم بلوغ الحد الأقصى للمفاتيح", - "apiKeys.dialog.maxDesc": "لقد وصلت إلى الحد الأقصى وهو 10 مفاتيح API. يرجى إلغاء مفتاح حالي قبل إنشاء واحد جديد.", - "apiKeys.dialog.close": "إغلاق", - "apiKeys.dialog.generated": "تم إنشاء مفتاح API!", - "apiKeys.dialog.generatedDesc": "تم إنشاء مفتاح API الجديد. انسخه الآن - لن يظهر مرة أخرى.", - "apiKeys.dialog.important": "مهم:", - "apiKeys.dialog.importantDesc": "هذه هي المرة الوحيدة التي سترى فيها هذا المفتاح. احفظه في مكان آمن.", - "apiKeys.dialog.apiKey": "مفتاح API", - "apiKeys.dialog.name": "الاسم:", - "apiKeys.dialog.done": "تم", - "apiKeys.dialog.copied": "لقد نسخت المفتاح", - "apiKeys.dialog.generateTitle": "إنشاء مفتاح API جديد", - "apiKeys.dialog.generateDesc": "إنشاء مفتاح API جديد للوصول البرمجي إلى واجهة الترجمة.", - "apiKeys.dialog.keyName": "اسم المفتاح (اختياري)", - "apiKeys.dialog.keyNamePlaceholder": "مثال: الإنتاج، الاختبار", - "apiKeys.dialog.keyNameHint": "اسم وصفي لمساعدتك على التعرف على هذا المفتاح لاحقًا.", - "apiKeys.dialog.nameTooLong": "يجب ألا يتجاوز الاسم {max} حرفًا", - "apiKeys.dialog.nameInvalid": "يمكن أن يحتوي الاسم على أحرف وأرقام ومسافات وشرطات وشرطات سفلية فقط", - "apiKeys.dialog.cancel": "إلغاء", - "apiKeys.dialog.generating": "جارٍ الإنشاء...", - "apiKeys.dialog.generate": "إنشاء مفتاح", - "apiKeys.table.name": "الاسم", - "apiKeys.table.prefix": "البادئة", - "apiKeys.table.created": "تاريخ الإنشاء", - "apiKeys.table.lastUsed": "آخر استخدام", - "apiKeys.table.never": "أبدًا", - "apiKeys.table.actions": "الإجراءات", - "apiKeys.table.revoke": "إلغاء", - "apiKeys.table.copyPrefix": "نسخ بادئة المفتاح", - "apiKeys.table.revokeKey": "إلغاء المفتاح", - "apiKeys.revokeDialog.title": "إلغاء مفتاح API", - "apiKeys.revokeDialog.desc": "هل أنت متأكد من إلغاء المفتاح \"{name}\"؟ لا يمكن التراجع عن هذا الإجراء.", - "apiKeys.revokeDialog.confirm": "نعم، إلغاء", - "apiKeys.revokeDialog.cancel": "إلغاء", - "context.proTitle": "ميزة Pro", - "context.proDesc": "السياق والمصطلحات المهنية متاحة مع خطط Pro وBusiness وEnterprise. توفر ترجمات أكثر دقة من خلال تعليمات ومفردات خاصة بمجالك.", - "context.viewPlans": "عرض الخطط", - "context.title": "السياق والمصطلحات", - "context.subtitle": "حسّن جودة الترجمة من خلال تعليمات ومفردات خاصة بمجالك.", - "context.presets.title": "المصطلحات المهنية", - "context.presets.desc": "تحميل مصطلحات كاملة مع تعليمات ومصطلحات متخصصة", - "context.instructions.title": "تعليمات السياق", - "context.instructions.desc": "تعليمات سيتبعها الذكاء الاصطناعي أثناء الترجمة", - "context.instructions.placeholder": "مثال: أنت تترجم مستندات تقنية HVAC. استخدم مصطلحات الهندسة الدقيقة...", - "context.glossary.title": "المصطلحات التقنية", - "context.glossary.desc": "التنسيق: source=target (واحد في كل سطر). المصطلحات المحملة عبر الإعدادات المسبقة قابلة للتعديل.", - "context.glossary.terms": "مصطلحات في القاموس", - "context.clearAll": "مسح الكل", - "context.saving": "جارٍ الحفظ...", - "context.save": "حفظ", - "translate.glossary.title": "المسرد", - "translate.glossary.select": "اختر مسرداً", - "translate.glossary.none": "بدون", - "translate.glossary.terms": "مصطلحات", - "translate.glossary.proOnly": "قم بالترقية إلى Pro لاستخدام المصطلحات", - "translate.glossary.myGlossaries": "مصطلحاتي", - "translate.glossary.fromTemplate": "إنشاء من قالب", - "translate.glossary.noGlossaryForPair": "لا مصطلحات لـ", - "translate.glossary.noGlossaries": "لا مصطلحات", - "translate.glossary.loading": "جاري التحميل...", - "translate.glossary.classicMode": "محرك محايد بدون مسرد (AI فقط)", - "translate.glossary.selectPlaceholder": "اختر مسرداً...", - "translate.glossary.multilingual": "متعدد اللغات", - "translate.glossary.noGlossaryAvailable": "لا يوجد مسرد متاح", - "translate.glossary.filterByLang": "تصفية حسب اللغة", - "translate.glossary.active": "نشط", - "translate.glossary.inactive": "غير نشط", - "translate.glossary.availableTemplates": "القوالب المتاحة", - "translate.glossary.importing": "جاري الاستيراد...", - "translate.glossary.imported": "(مستورد)", - "translate.glossary.noGlossaryForSource": "لا يوجد مسرد أو قالب للغة المصدر", - "translate.glossary.createGlossary": "إنشاء مسرد", - "translate.glossary.showAll": "عرض جميع المسارد", - "translate.glossary.activePreview": "معاينة التطابقات النشطة:", - "translate.glossary.total": "الإجمالي", - "translate.glossary.moreTerms": "مصطلحات إضافية", - "translate.glossary.noTerms": "لا توجد مصطلحات في هذا المسرد.", - "translate.glossary.sourceTerm": "مصطلح المصدر", - "translate.glossary.translation": "الترجمة", - "translate.glossary.addTerm": "إضافة مصطلح", - "translate.glossary.disabledMode": "محرك محايد بدون مسرد مطبق", - "translate.glossary.addTermError": "خطأ في إضافة المصطلح", - "translate.glossary.networkError": "خطأ في الشبكة", - "translate.glossary.importFailed": "فشل الاستيراد ({status})", - "translate.glossary.helpText": "يسرد المسرد ترجمة دقيقة للمصطلحات. اختر مسرداً تطابق لغته المصدر اللغة الأصلية لمستندك.", - "translate.glossary.sourceWarning": "تحذير: هذا المسرد يستخدم لغة المصدر", - "translate.glossary.sourceWarningBut": "ولكن مستندك مهيأ بـ", - "translate.glossary.targetWarning": "عدم توافق الهدف: هذا المسرد مصمم للترجمة إلى", - "translate.glossary.targetWarningBut": "ولكن مستندك يستهدف", - "translate.glossary.targetWarningEnd": "قد لا تكون المصطلحات ذات صلة.", - "context.presets.createGlossary": "إنشاء مسرد", - "context.presets.created": "تم إنشاء المسرد", - "context.presets.createdDesc": "تم إنشاء المسرد \"{name}\" بـ {count} مصطلحات.", - "context.presets.hint": "انقر على إعداد مسبق لإنشاء مسرد بمصطلحات خاصة بالمجال. أد穹 مصادرك في قسم المسرات.", - "context.glossary.manage": "إدارة المسرات", - "context.saved": "تم الحفظ", - "context.savedDesc": "تم حفظ تعليمات السياق الخاصة بك.", - "admin.login.title": "الإدارة", - "admin.login.required": "تسجيل الدخول مطلوب", - "admin.login.password": "كلمة مرور المسؤول", - "admin.login.connecting": "جارٍ الاتصال...", - "admin.login.access": "الدخول إلى لوحة الإدارة", - "admin.login.restricted": "مخصص للمسؤولين فقط", - "admin.layout.checking": "جارٍ التحقق من المصادقة...", - "admin.dashboard.title": "لوحة تحكم المسؤول", - "admin.dashboard.subtitle": "لوحة تحكم المسؤولين", - "admin.dashboard.refresh": "تحديث", - "admin.dashboard.refreshTooltip": "تحديث بيانات لوحة التحكم", - "admin.dashboard.config": "إعدادات النظام", - "admin.dashboard.maxFileSize": "الحد الأقصى لحجم الملف:", - "admin.dashboard.translationService": "خدمة الترجمة:", - "admin.dashboard.formats": "التنسيقات:", - "admin.nav.dashboard": "Dashboard", - "admin.nav.users": "المستخدمون", - "admin.nav.pricing": "الأسعار و Stripe", - "admin.nav.providers": "المزوّدون", - "admin.nav.system": "النظام", - "admin.nav.logs": "السجلات", - "admin.users.title": "إدارة المستخدمين", - "admin.users.subtitle": "عرض حسابات المستخدمين وإدارتها", - "admin.users.planUpdated": "تم تحديث الخطة", - "admin.users.planChanged": "تم تغيير الخطة إلى \"{plan}\" بنجاح.", - "admin.users.unknownError": "خطأ غير معروف", - "admin.users.error": "خطأ", - "admin.users.planUpdateError": "تعذر تحديث الخطة: {message}", - "admin.users.noKeys": "لا توجد مفاتيح", - "admin.users.noKeysDesc": "لا يمتلك هذا المستخدم مفاتيح API نشطة.", - "admin.users.keysRevoked": "تم إلغاء المفاتيح", - "admin.users.keysRevokedDesc": "تم إلغاء {count} مفتاح API بنجاح.", - "admin.users.revokeError": "تعذر إلغاء المفاتيح: {message}", - "admin.users.retry": "إعادة المحاولة", - "admin.system.title": "النظام", - "admin.system.subtitle": "مراقبة حالة النظام وإدارة الموارد", - "admin.system.quotas": "حصص الترجمة", - "admin.system.resetQuotas": "إعادة تعيين الحصص الشهرية", - "admin.system.resetting": "جارٍ إعادة التعيين...", - "admin.system.reset": "إعادة تعيين", - "admin.system.allOperational": "جميع الأنظمة تعمل بشكل طبيعي", - "admin.system.issuesDetected": "تم اكتشاف مشاكل في النظام", - "admin.system.waitingData": "في انتظار البيانات...", - "admin.system.purging": "جارٍ الحذف...", - "admin.system.clean": "تنظيف", - "admin.system.purge": "حذف", - "memento.title": "اكتشف Momento", - "memento.slogan": "Momento ليس مجرد تطبيق ملاحظات. إنه نظام بيئي ذكي يربط ويحلل ويطور أفكارك في الوقت الفعلي باستخدام 6 وكلاء ذكاء اصطناعي وبحث دلالي متقدم.", - "memento.ctaFree": "ابدأ مجاناً", - "memento.ctaMore": "اعرف المزيد", - "common.backToHome": "العودة للرئيسية", - "dashboard.topbar.interfaceLabel": "واجهة الترجمة", - "dashboard.topbar.premiumAccess": "وصول مميز", - "landing.hero.contextEngine": "ترجمة مكتشفة: مصطلح صيانة تقني لأنظمة التدفئة والتهوية...", - "landing.hero.liveAnalysis": "تحليل مباشر", - "landing.hero.termsDetected": "مصطلحات مكتشفة", - "landing.steps.process": "العملية", - "landing.translate.newProject": "مشروع جديد", - "landing.translate.title": "ترجمة مستند", - "landing.translate.subtitle": "استورد ملفًا واختر اللغة المستهدفة", - "landing.translate.sourceDocument": "المستند المصدر", - "landing.translate.configuration": "الإعدادات", - "landing.translate.sourceLang": "لغة المصدر", - "landing.translate.targetLang": "اللغة المستهدفة", - "landing.translate.provider": "المزود", - "landing.translate.startTranslation": "بدء الترجمة", - "landing.translate.zeroRetention": "صفر احتفاظ", - "landing.translate.filesDeleted": "الملفات محذوفة بعد المعالجة", - "landing.translate.dropHere": "اسحب وأفلت هنا", - "landing.translate.supportedFormats": "ملفات DOCX, XLSX, PPTX أو PDF مدعومة", - "landing.translate.aiAnalysis": "تحليل AI نشط", - "landing.translate.processing": "جاري المعالجة", - "landing.translate.preservingLayout": "جاري الحفاظ على التنسيق", - "layout.nav.apiAccess": "وصول API", - "layout.footer.terms": "الشروط", - "layout.footer.privacy": "الخصوصية", - "fileUploader.uploadDocument": "تحميل المستند", - "fileUploader.uploadDesc": "اسحب وأفلت أو انقر لتحديد ملف (Excel, Word, PowerPoint)", - "fileUploader.dropHere": "أفلت ملفك هنا…", - "fileUploader.dragAndDrop": "اسحب وأفلت المستند هنا", - "fileUploader.orClickBrowse": "أو انقر للتصفح", - "fileUploader.preview": "معاينة", - "fileUploader.translationOptions": "خيارات الترجمة", - "fileUploader.configureSettings": "اضبط إعدادات الترجمة", - "fileUploader.targetLanguage": "اللغة المستهدفة", - "fileUploader.selectLanguage": "اختر اللغة", - "fileUploader.translationProvider": "مزود الترجمة", - "fileUploader.selectProvider": "اختر المزود", - "fileUploader.advancedOptions": "خيارات متقدمة", - "fileUploader.translateImages": "ترجمة الصور", - "fileUploader.translating": "جارٍ الترجمة…", - "fileUploader.translateDocument": "ترجمة المستند", - "fileUploader.processing": "جارٍ المعالجة…", - "fileUploader.translationError": "خطأ في الترجمة", - "fileUploader.translationComplete": "اكتملت الترجمة!", - "fileUploader.translationCompleteDesc": "تمت ترجمة مستندك بنجاح مع الحفاظ على جميع التنسيقات.", - "fileUploader.download": "تنزيل المستند المترجم", - "fileUploader.webgpuUnsupported": "WebGPU غير مدعوم في هذا المتصفح. يرجى استخدام Chrome 113+ أو Edge 113+.", - "fileUploader.webllmNotLoaded": "نموذج WebLLM غير محمّل. اذهب إلى الإعدادات > خدمات الترجمة لتحميل نموذج أولاً.", - "fileUploader.extracting": "استخراج النصوص من المستند…", - "fileUploader.noTranslatable": "لم يتم العثور على نص قابل للترجمة في المستند", - "fileUploader.foundTexts": "تم العثور على {count} نصوص للترجمة", - "fileUploader.translatingItem": "ترجمة {current}/{total}: \"{preview}\"", - "fileUploader.reconstructing": "إعادة بناء المستند…", - "fileUploader.translatingLocally": "ترجمة محلية باستخدام WebLLM…", - "checkout.activating": "جارٍ التفعيل…", - "checkout.activatingDesc": "نقوم بتحديث اشتراكك، يرجى الانتظار.", - "checkout.paymentConfirmed": "تم تأكيد الدفع!", - "checkout.subscriptionActivated": "تم تفعيل الاشتراك!", - "checkout.planActivated": "تم تفعيل خطة {plan}!", - "checkout.redirectingToProfile": "إعادة التوجيه إلى ملفك الشخصي…", - "checkout.paymentReceived": "تم استلام الدفع", - "checkout.redirecting": "جارٍ إعادة التوجيه…", - "checkout.syncError": "خطأ في المزامنة", - "checkout.networkError": "خطأ في الشبكة. تم تأكيد الدفع — يرجى إعادة تحميل ملفك الشخصي.", - "dashboard.checkoutSyncError": "خطأ في مزامنة الدفع.", - "dashboard.networkRefresh": "خطأ في الشبكة. يرجى تحديث الصفحة.", - "dashboard.continueToTranslate": "متابعة إلى الترجمة", - "langSelector.search": "بحث…", - "langSelector.noResults": "لا توجد نتائج", - "langSelector.source": "المصدر", - "langSelector.target": "الهدف", - "langSelector.swap": "تبديل", - "translateComplete.highQuality": "جودة عالية", - "translateComplete.segments": "المقاطع", - "translateComplete.characters": "الأحرف", - "translateComplete.confidence": "الثقة", - "providerTheme.deepseek.badge": "أساسي", - "providerTheme.deepseek.subBadge": "تقني واقتصادي", - "providerTheme.deepseek.desc": "ترجمة فائقة الدقة واقتصادية، مثالية للمستندات التقنية والبرمجة.", - "providerTheme.openai.badge": "مميز", - "providerTheme.openai.subBadge": "دقة عالية", - "providerTheme.openai.desc": "معيار الذكاء الاصطناعي العالمي. أقصى اتساق نصي واحترام صارم للأسلوب.", - "providerTheme.minimax.badge": "متقدم", - "providerTheme.minimax.subBadge": "الأداء", - "providerTheme.minimax.desc": "سرعة تنفيذ مذهلة وفهم ممتاز للهياكل المعقدة.", - "providerTheme.openrouter.badge": "سريع", - "providerTheme.openrouter.subBadge": "متعدد النماذج", - "providerTheme.openrouter.desc": "وصول موحد إلى أفضل النماذج مفتوحة المصدر المحسّنة للترجمة.", - "providerTheme.openrouter_premium.badge": "فائق", - "providerTheme.openrouter_premium.subBadge": "السياق الأقصى", - "providerTheme.openrouter_premium.desc": "مدعوم من أحدث النماذج (GPT-4o، Claude Sonnet 4.6) للمستندات الطويلة.", - "providerTheme.zai.badge": "متخصص", - "providerTheme.zai.subBadge": "المال والقانون", - "providerTheme.zai.desc": "نموذج مضبوط بدقة للمصطلحات التجارية المتطلبة (قانونية، مالية).", - "providerTheme.default.badge": "حديث", - "providerTheme.default.subBadge": "تفكير الذكاء الاصطناعي", - "providerTheme.default.desc": "ترجمة بنموذج لغوي كبير (LLM) مع تحليل دلالي متقدم.", - "providerTheme.classic.google.label": "ترجمة Google", - "providerTheme.classic.google.desc": "ترجمة فائقة السرعة تغطي أكثر من 130 لغة. موصى بها للتدفقات العامة.", - "providerTheme.classic.deepl.label": "DeepL Pro", - "providerTheme.classic.deepl.desc": "ترجمة عالية الدقة مشهور بسيولتها وصياغاتها الطبيعية.", - "providerTheme.classic.google_cloud.label": "Google Cloud API", - "providerTheme.classic.google_cloud.desc": "محرك سحابي احترافي محسّن لمعالجة كميات كبيرة من المستندات.", - "providerSelector.noClassic": "لا يوجد مترجم قياسي متاح.", - "providerSelector.noLlm": "لم يتم تكوين نموذج ذكاء اصطناعي.", - "providerSelector.costOne": "التكلفة: رصيد واحد لكل صفحة", - "providerSelector.costFive": "التكلفة: 5 أرصدة لكل صفحة (عامل مميز)", - "providerSelector.unlockContextual": "افتح الترجمة السياقية المتميزة لمستنداتك بالكامل.", - "translate.header.processing": "جارٍ المعالجة", - "translate.header.aiActive": "تحليل الذكاء الاصطناعي نشط", - "translate.header.aiActiveDesc": "يتم الحفاظ على تخطيطك بواسطة محركنا السياقي.", - "translate.header.completed": "مكتمل", - "translate.header.completedTitle": "اكتملت الترجمة", - "translate.header.proSpace": "مساحة Pro", - "translate.header.translateDoc": "ترجمة مستند", - "translate.header.translateDocDesc": "حافظ على التخطيط الأصلي من خلال محرك الترجمة فائق الدقة.", - "translate.upload.nativeFormat": "التنسيق الأصلي", - "translate.fileType.word": "Word (.docx)", - "translate.fileType.excel": "Excel (.xlsx)", - "translate.fileType.slides": "شرائح (.pptx)", - "translate.fileType.pdf": "PDF (.pdf)", - "translate.startTranslation": "بدء الترجمة", - "translate.submit": "جارٍ الإرسال…", - "translate.chooseTargetLang": "يرجى اختيار لغة مستهدفة", - "translate.pleaseLoadFile": "يرجى تحميل ملف أولاً", - "translate.contextEngineActive": "المحرك السياقي نشط", - "translate.phase1": "المرحلة 1: التهيئة", - "translate.phase2": "المرحلة 2: إعادة البناء السياقي", - "translate.stat.segments": "مقاطع", - "translate.stat.precision": "الدقة", - "translate.stat.speedLabel": "السرعة", - "translate.stat.turbo": "تيربو", - "translate.stat.time": "الوقت", - "translate.complete.masterQuality": "✓ جودة رئيسية", - "translate.download": "تنزيل", - "translate.newTranslation": "+ ترجمة جديدة", - "translate.failedTitle": "خطأ في الترجمة", - "translate.retry": "إعادة المحاولة", - "translate.uploadAnother": "تحميل ملف آخر", - "translate.monitor": "مراقب الذكاء الاصطناعي", - "translate.summary": "ملخص", - "translate.cancelProcess": "⟳ إلغاء العملية", - "translate.layoutIntegrity": "سلامة التخطيط", - "translate.secureHundred": "100% آمن", - "translate.okHundred": "100% OK", - "translate.preserveLayout": "الحفاظ على التخطيط", - "translate.preserveLayoutDesc": "الحفاظ على التخطيط", - "translate.textOnly": "نص فقط", - "translate.textOnlyDesc": "ترجمة سريعة للنص فقط", - "translate.unavailableStandard": "غير متاح في الوضع القياسي (AI فقط)", - "apiKeys.noKeysGenerated": "لم يتم إنشاء مفاتيح", - "apiKeys.copied": "تم النسخ!", - "services.fallback.google.label": "ترجمة Google", - "services.fallback.google.desc": "ترجمة سريعة، أكثر من 130 لغة", - "settings.formats.excel.name": "Excel", - "settings.formats.word.name": "Word", - "settings.formats.powerpoint.name": "PowerPoint", - "pricing.dashboard": "لوحة التحكم", - "pricing.okSymbol": "✓", - "pricing.errSymbol": "✕", - }, - - // PERSIAN (fa) - // ═══════════════════════════════════════════════════════════════ - fa: { -"auth.brandName": "Wordly", - "dashboard.nav.translate": "ترجمه", - "dashboard.nav.profile": "پروفایل من", - "dashboard.nav.settings": "تنظیمات", - "dashboard.nav.context": "زمینه", - "dashboard.nav.services": "خدمات", - "dashboard.nav.apiKeys": "کلیدهای API", - "dashboard.nav.glossaries": "واژه‌نامه‌ها", - "dashboard.header.title": "داشبورد", - "dashboard.header.subtitle": "مدیریت ترجمه‌های شما", - "dashboard.header.toggleMenu": "منو", - "dashboard.header.profileTitle": "پروفایل من", - "dashboard.sidebar.theme": "پوسته", - "dashboard.sidebar.signOut": "خروج", - "dashboard.sidebar.backHome": "بازگشت به صفحه اصلی", - "dashboard.sidebar.upgradeToPro": "ارتقا به Pro ←", - "cookieConsent.title": "کوکی‌ها در Wordly", - "cookieConsent.description": "ما از کوکی‌های ضروری برای کارکرد برنامه استفاده می‌کنیم (نشست، امنیت، زبان). با اجازه شما، از کوکی‌های اختیاری برای اندازه‌گیری ترافیک و بهبود محصول نیز استفاده می‌کنیم.", - "cookieConsent.acceptAll": "پذیرش همه", - "cookieConsent.essentialOnly": "فقط ضروری", - "cookieConsent.learnMore": "بیشتر بدانید", - "login.orContinueWith": "یا با ایمیل ادامه دهید", - "login.google.connecting": "در حال اتصال…", - "login.google.errorGeneric": "خطایی در ورود با Google رخ داد.", - "login.google.errorFailed": "ورود با Google ناموفق بود. دوباره تلاش کنید.", - "landing.nav.why": "چرا ما؟", - "landing.nav.formats": "قالب‌ها", - "landing.nav.pricing": "قیمت‌ها", - "landing.nav.login": "ورود", - "landing.nav.startFree": "شروع رایگان", - "landing.hero.tag": "هوش مصنوعی حرفه‌ای اسناد", - "landing.hero.titleLine1": "اسناد خود را ترجمه کنید.", - "landing.hero.titleLine2": "با قالب‌بندی بی‌نقص.", - "landing.hero.description": "تنها مترجمی که SmartArt، نمودارها، فهرست مطالب، اشکال و طرح‌بندی‌های پیچیده را دقیقاً به شکلی که بوده حفظ می‌کند.", - "landing.hero.ctaMain": "شروع رایگان — ۲ سند/ماه", - "landing.hero.ctaSec": "مشاهده طرح‌ها", - "landing.hero.deleted": "فایل‌ها پس از ۶۰ دقیقه حذف می‌شوند", - "landing.hero.noHidden": "بدون هزینه پنهان", - "landing.hero.preview": "پیش‌نمایش قبل از پرداخت", - "landing.hero.formattedOk": "قالب‌بندی صحیح", - "landing.hero.aiActive": "ترجمه هوش مصنوعی فعال", - "landing.steps.title": "چگونه کار می‌کند؟", - "landing.steps.subtitle": "سه مرحله. صفر افت قالب‌بندی.", - "landing.steps.step1.num": "01", - "landing.steps.step1.title": "فایل خود را آپلود کنید", - "landing.steps.step1.desc": "فایل Excel، Word، PowerPoint یا PDF خود را بکشید و رها کنید.", - "landing.steps.step2.num": "02", - "landing.steps.step2.title": "زبان و موتور را انتخاب کنید", - "landing.steps.step2.desc": "زبان هدف و موتور را انتخاب کنید — کلاسیک یا هوش مصنوعی با درک زمینه.", - "landing.steps.step3.num": "03", - "landing.steps.step3.title": "نتیجه را دانلود کنید", - "landing.steps.step3.desc": "سند ترجمه‌شده با قالب‌بندی کاملاً مشابه اصل را دریافت کنید.", - "landing.features.tag": "موتور ترجمه هوش مصنوعی", - "landing.features.title": "ترجمه‌ای که تخصص شما را می‌فهمد", - "landing.features.description": "مدل‌های هوش مصنوعی ما زمینه را تحلیل می‌کنند، اصطلاحات شما را رعایت می‌کنند و حتی متن داخل تصاویر را ترجمه می‌کنند.", - "landing.features.context.title": "زمینه صنعت", - "landing.features.context.desc": "صنعت خود را توصیف کنید و ترجمه‌های تخصصی دریافت کنید، نه عمومی.", - "landing.features.glossary.title": "واژه‌نامه‌های تخصصی", - "landing.features.glossary.desc": "اصطلاحات فنی خود را تعریف کنید. CTA به معنی «واحد پردازش هوا» باقی می‌ماند، نه «فراخوان اقدام».", - "landing.features.vision.title": "تشخیص تصویر", - "landing.features.vision.desc": "متن تعبیه‌شده در تصاویر، نمودارها و گراف‌ها شناسایی و ترجمه می‌شود.", - "landing.features.demo.source": "مبدأ (FR)", - "landing.features.demo.google": "Google Translate", - "landing.features.demo.ours": "هوش مصنوعی ما", - "landing.layout.title": "قالب‌بندی شما،", - "landing.layout.title2": "کاملاً حفظ شده", - "landing.layout.subtitle": "سایر مترجم‌ها طرح‌بندی شما را خراب می‌کنند. ما نه.", - "landing.layout.p1.title": "SmartArt و نمودارها", - "landing.layout.p1.desc": "نمودارهای سازمانی، فلوچارت، سلسله‌مراتب — همه دقیقاً ترجمه شده.", - "landing.layout.p2.title": "فهرست مطالب", - "landing.layout.p2.desc": "مدخل‌های فهرست مطالب، شماره صفحات و ارجاعات متقاطع به‌درستی به‌روزرسانی می‌شوند.", - "landing.layout.p3.title": "نمودارها و گراف‌ها", - "landing.layout.p3.desc": "عناوین، برچسب‌های محور، راهنماها و نام سری‌ها — همه ترجمه شده.", - "landing.layout.p4.title": "اشکال و جعبه‌های متن", - "landing.layout.p4.desc": "مستطیل‌ها، بلوک‌های گرد، یادداشت‌ها — در همه‌جا بومی‌سازی شده.", - "landing.layout.p5.title": "سرصفحه و پاصفحه", - "landing.layout.p5.desc": "سرصفحه، پاصفحه و پاورقی هرگز فراموش نمی‌شوند.", - "landing.layout.p6.title": "۱۳۰+ زبان", - "landing.layout.p6.desc": "Google Translate، DeepL و موتورهای هوش مصنوعی حرفه‌ای.", - "landing.formats.title": "هر قالبی،", - "landing.formats.title2": "هر عنصری", - "landing.formats.subtitle": "آنچه دیگران فراموش می‌کنند را ترجمه می‌کنیم. کسب‌وکار شما مستندات بی‌نقص را شایسته است.", - "landing.formats.word.name": "Word", - "landing.formats.word.i1": "پاراگراف‌ها و عناوین", - "landing.formats.word.i2": "جداول و نمودارها", - "landing.formats.word.i3": "نمودارهای SmartArt", - "landing.formats.word.i4": "فهرست مطالب", - "landing.formats.word.i5": "سرصفحه و پاصفحه", - "landing.formats.word.i6": "اشکال و جعبه‌های متن", - "landing.formats.word.i7": "پاورقی و یادداشت‌های پایانی", - "landing.formats.excel.name": "Excel", - "landing.formats.excel.i1": "مقادیر سلول", - "landing.formats.excel.i2": "نام برگه‌ها", - "landing.formats.excel.i3": "نمودارها و برچسب‌ها", - "landing.formats.excel.i4": "سرصفحه و پاصفحه", - "landing.formats.excel.i5": "سلول‌های ادغام‌شده حفظ می‌شوند", - "landing.formats.pptx.name": "PowerPoint", - "landing.formats.pptx.i1": "متن اسلاید و یادداشت‌ها", - "landing.formats.pptx.i2": "نمودارها و گراف‌ها", - "landing.formats.pptx.i3": "اشکال و جعبه‌های متن", - "landing.formats.pptx.i4": "طرح‌بندی‌های اصلی", - "landing.formats.pptx.i5": "انیمیشن‌ها حفظ می‌شوند", - "landing.formats.pdf.name": "PDF", - "landing.formats.pdf.i1": "PDFهای متنی", - "landing.formats.pdf.i2": "طرح‌بندی حفظ شده", - "landing.formats.pdf.i3": "تصاویر در جای خود", - "landing.formats.pdf.i4": "جداول حفظ شده", - "landing.formats.pdf.i5": "خروجی به صورت DOCX یا PDF", - "landing.pricing.title": "قیمت‌های ساده و شفاف", - "landing.pricing.subtitle": "آنچه می‌بینید همان چیزی است که پرداخت می‌کنید. بدون هزینه پنهان.", - "landing.pricing.monthly": "ماهانه", - "landing.pricing.annual": "سالانه", - "landing.pricing.bestValue": "محبوب‌ترین", - "landing.pricing.month": "/ماه", - "landing.pricing.footer": "قیمت نمایش‌داده‌شده همان قیمتی است که پرداخت می‌کنید. بدون هزینه پنهان پس از ترجمه.", - "landing.pricing.starter.name": "Starter", - "landing.pricing.starter.desc": "برای افراد و پروژه‌های کوچک", - "landing.pricing.starter.f1": "۵۰ سند / ماه", - "landing.pricing.starter.f2": "تا ۵۰ صفحه برای هر سند", - "landing.pricing.starter.f3": "Google Translate + DeepL", - "landing.pricing.starter.f4": "فایل‌ها تا ۱۰ مگابایت", - "landing.pricing.starter.cta": "شروع کنید", - "landing.pricing.pro.name": "Pro", - "landing.pricing.pro.desc": "برای متخصصان حرفه‌ای", - "landing.pricing.pro.f1": "۲۰۰ سند / ماه", - "landing.pricing.pro.f2": "تا ۲۰۰ صفحه برای هر سند", - "landing.pricing.pro.f3": "ترجمه مبتنی بر هوش مصنوعی", - "landing.pricing.pro.f4": "Google + DeepL شامل است", - "landing.pricing.pro.f5": "واژه‌نامه و پرامپت سفارشی", - "landing.pricing.pro.f6": "پشتیبانی اولویت‌دار", - "landing.pricing.pro.cta": "Pro را امتحان کنید", - "landing.pricing.business.name": "سازمانی", - "landing.pricing.business.desc": "برای تیم‌ها با نیاز بالا", - "landing.pricing.business.f1": "۱,۰۰۰ سند / ماه", - "landing.pricing.business.f2": "تا ۵۰۰ صفحه برای هر سند", - "landing.pricing.business.f3": "هوش مصنوعی پیشرفته (Claude)", - "landing.pricing.business.f4": "همه ارائه‌دهندگان + API", - "landing.pricing.business.f5": "وب‌هوک و خودکارسازی", - "landing.pricing.business.f6": "۵ صندلی تیمی", - "landing.pricing.business.cta": "تماس با ما", - "landing.cta.title": "در ۳۰ ثانیه ترجمه را شروع کنید", - "landing.cta.subtitle": "بدون نیاز به کارت بانکی. همین الان رایگان امتحان کنید و به اسناد چندزبانه خود زندگی دوباره ببخشید.", - "landing.cta.button": "ایجاد حساب رایگان", - "landing.cta.secure": "محافظت‌شده با رمزنگاری AES-256", - "landing.footer.desc": "متخصص ترجمه هوشمند اسناد. هنر طرح‌بندی را با علم هوش مصنوعی زمینه‌محور ترکیب می‌کنیم.", - "landing.footer.product": "محصول", - "landing.footer.resources": "منابع", - "landing.footer.legal": "حقوقی", - "landing.footer.rights": "© 2026 Wordly.art — تمامی حقوق محفوظ است.", - "dashboard.translate.pageTitle": "ترجمه یک سند", - "dashboard.translate.pageSubtitle": - "یک فایل وارد کنید و زبان هدف را انتخاب کنید", - "dashboard.translate.errorNotificationTitle": "خطا", - "dashboard.translate.dropzone.uploadAria": "منطقه رها کردن فایل", - "dashboard.translate.dropzone.title": "فایل خود را اینجا بکشید و رها کنید", - "dashboard.translate.dropzone.subtitle": - "یا کلیک کنید برای انتخاب (DOCX, XLSX, PPTX, PDF)", - "dashboard.translate.dropzone.replaceFile": "جایگزینی فایل", - "dashboard.translate.language.source": "زبان مبدأ", - "dashboard.translate.language.target": "زبان مقصد", - "dashboard.translate.language.loading": "در حال بارگذاری زبان‌ها…", - "dashboard.translate.language.autoDetect": "تشخیص خودکار", - "dashboard.translate.language.selectPlaceholder": "انتخاب…", - "dashboard.translate.language.loadErrorPrefix": - "بارگذاری زبان‌ها ناموفق بود", - "dashboard.translate.provider.loading": "در حال بارگذاری ارائه‌دهنده‌ها…", - "dashboard.translate.provider.noneConfigured": "هیچ ارائه‌دهنده‌ای پیکربندی نشده", - "dashboard.translate.provider.modelTitle": "مدل", - "dashboard.translate.provider.sectionTitle": "ارائه‌دهنده", - "dashboard.translate.provider.llmDivider": "هوش مصنوعی · آگاه به زمینه", - "dashboard.translate.provider.llmDividerPro": - "هوش مصنوعی · آگاه به زمینه (حرفه‌ای)", - "dashboard.translate.provider.upgrade": "ارتقا به حرفه‌ای", - "dashboard.translate.provider.upgradeSuffix": - "برای دسترسی به ترجمه هوش مصنوعی", - "dashboard.translate.trust.zeroRetention": "بدون نگهداری", - "dashboard.translate.trust.deletedAfter": - "فایل‌ها پس از پردازش حذف می‌شوند", - "dashboard.translate.actions.uploading": "در حال بارگذاری…", - "dashboard.translate.actions.translate": "ترجمه", - "dashboard.translate.actions.filePrefix": "فایل: ", - "dashboard.translate.actions.cancel": "انصراف", - "dashboard.translate.actions.tryAgain": "تلاش دوباره", - "dashboard.translate.steps.uploading": "در حال بارگذاری فایل…", - "dashboard.translate.steps.starting": "در حال شروع ترجمه…", - "dashboard.translate.complete.title": "ترجمه کامل شد!", - "dashboard.translate.complete.descNamed": - "فایل {name} شما با موفقیت ترجمه شد.", - "dashboard.translate.complete.descGeneric": - "فایل شما با موفقیت ترجمه شد.", - "dashboard.translate.complete.downloading": "در حال دانلود…", - "dashboard.translate.complete.download": "دانلود", - "dashboard.translate.complete.newTranslation": "ترجمه جدید", - "dashboard.translate.complete.toastOkTitle": "موفقیت", - "dashboard.translate.complete.toastOkDesc": "{name} با موفقیت بارگیری شد.", - "dashboard.translate.complete.toastFailTitle": "ناموفق", - "dashboard.translate.complete.toastFailDesc": - "ترجمه ناموفق بود. لطفاً دوباره تلاش کنید.", - "dashboard.translate.sourceDocument": "سند مبدأ", - "dashboard.translate.configuration": "پیکربندی", - "dashboard.translate.translating": "در حال ترجمه", - "dashboard.translate.liveMonitor": "مانیتور زنده", - "dashboard.translate.summary": "خلاصه", - "dashboard.translate.engine": "موتور", - "dashboard.translate.confidence": "اطمینان", - "dashboard.translate.cancel": "لغو", - "dashboard.translate.segments": "بخش‌ها", - "dashboard.translate.characters": "نویسه‌ها", - "dashboard.translate.elapsed": "گذشته", - "dashboard.translate.segPerMin": "بخش/دقیقه", - "dashboard.translate.highQuality": "کیفیت بالا", - "dashboard.translate.quality": "کیفیت", - "dashboard.translate.completed": "ترجمه انجام شد", - "dashboard.translate.replace": "جایگزینی", - "dashboard.translate.pdfMode.title": "حالت ترجمه PDF", - "dashboard.translate.pdfMode.preserveLayout": "حفظ چیدمان", - "dashboard.translate.pdfMode.textOnly": "فقط متن", - "dashboard.translate.pdfMode.preserveLayoutDesc": "تصاویر، جداول و قالب‌بندی را حفظ می‌کند. مناسب PDFهای ساده.", - "dashboard.translate.pdfMode.textOnlyDesc": "تمام متن را کاملاً ترجمه می‌کند. خروجی تمیز، بدون مشکل چیدمان.", - "dashboard.translate.pipeline.upload": "بارگذاری", - "dashboard.translate.pipeline.analyze": "تحلیل", - "dashboard.translate.pipeline.translate": "ترجمه", - "dashboard.translate.pipeline.rebuild": "بازسازی", - "dashboard.translate.pipeline.finalize": "نهایی‌سازی", - "dashboard.translate.progress.processingFallback": "در حال پردازش…", - "dashboard.translate.progress.connectionLost": "اتصال قطع شد. در حال تلاش مجدد…", - "dashboard.translate.progress.failedTitle": "ترجمه ناموفق", - "dashboard.translate.error.unexpected": "خطای غیرمنتظره‌ای رخ داد. لطفاً دوباره تلاش کنید.", - "dashboard.translate.error.noResult": "ترجمه نتیجه‌ای نداشت. تأیید کنید که سند حاوی متن است، سپس دوباره تلاش کنید یا موتور دیگری انتخاب کنید.", - "dashboard.translate.error.apiKey": "کلید API نامعتبر یا ناموجود است. با مدیر تماس بگیرید تا کلیدها را پیکربندی کند.", - "dashboard.translate.error.quota": "محدودیت استفاده به پایان رسیده. چند دقیقه دیگر دوباره تلاش کنید یا موتور دیگری انتخاب کنید.", - "dashboard.translate.error.timeout": "اتصال به سرویس ترجمه منقضی شد. شبکه خود را بررسی کنید و دوباره تلاش کنید.", - "dashboard.translate.error.sessionExpired": "نشست منقضی شده. برای شروع مجدد ترجمه روی تلاش مجدد کلیک کنید.", - "dashboard.translate.error.empty": "سند خالی به نظر می‌رسد یا متن قابل ترجمه‌ای ندارد (تصویر PDF اسکن شده؟).", - "dashboard.translate.error.unsupported": "فرمت فایل پشتیبانی نمی‌شود یا فایل خراب است.", - "dashboard.translate.error.connection": "اتصال قطع شد. شبکه خود را بررسی کنید و دوباره تلاش کنید.", - "dashboard.translate.error.generic": "ترجمه ناموفق: {detail}", - "dashboard.translate.error.title": "ترجمه ناموفق", - "dashboard.translate.retry": "تلاش مجدد ترجمه", - "dashboard.translate.newFile": "فایل جدید", - "dashboard.translate.modeAI": "حالت هوش مصنوعی", - "dashboard.translate.modeClassic": "حالت کلاسیک", - "dashboard.translate.glossaryLLMHint": "واژه‌نامه‌ها در حالت هوش مصنوعی موجودند", - "dashboard.translate.submitting": "در حال ارسال...", - "dashboard.translate.submit": "شروع ترجمه", - "dashboard.translate.noFile": "ابتدا یک فایل آپلود کنید", - "dashboard.translate.noTargetLang": "زبان مقصد را انتخاب کنید", - "glossaries.yourGlossaries": "واژه‌نامه‌های شما", - "glossaries.title": "واژه‌نامه‌ها و زمینه", - "glossaries.description": "واژه‌نامه‌ها و دستورالعمل‌های زمینه خود را برای ترجمه دقیق‌تر مدیریت کنید.", - "glossaries.createNew": "ایجاد جدید", - "glossaries.empty": "هنوز واژه‌نامه‌ای نیست", - "glossaries.emptyDesc": "اولین واژه‌نامه خود را ایجاد کنید یا یک پیش‌تنظیم حرفه‌ای بالا را بارگذاری کنید", - "glossaries.defineTerms": "واژه", - "glossaries.aboutTitle": "درباره واژه‌نامه‌ها", - "glossaries.aboutDesc": "واژه‌نامه‌ها به شما امکان تعریف ترجمه دقیق برای اصطلاحات خاص را می‌دهند. هنگام ترجمه، اصطلاحات واژه‌نامه برای اطمینان از ترجمه سازگار و دقیق استفاده می‌شوند.", - "glossaries.aboutFormat": "هر اصطلاح یک کلمه منبع و ترجمه‌هایی به چندین زبان دارد. در صفحه ترجمه یک واژه‌نامه را انتخاب کنید تا اعمال شود.", - "glossaries.toast.created": "واژه‌نامه ایجاد شد", - "glossaries.toast.createdDesc": "واژه‌نامه \"{name}\" ایجاد شد.", - "glossaries.toast.imported": "واژه‌نامه وارد شد", - "glossaries.toast.importedDesc": "واژه‌نامه \"{name}\" وارد شد.", - "glossaries.toast.updated": "واژه‌نامه به‌روزرسانی شد", - "glossaries.toast.updatedDesc": "واژه‌نامه \"{name}\" به‌روزرسانی شد.", - "glossaries.toast.deleted": "واژه‌نامه حذف شد", - "glossaries.toast.deletedDesc": "واژه‌نامه حذف شد.", - "glossaries.toast.error": "خطا", - "glossaries.toast.errorCreate": "ایجاد واژه‌نامه ناموفق بود", - "glossaries.toast.errorImport": "وارد کردن واژه‌نامه ناموفق بود", - "glossaries.toast.errorUpdate": "به‌روزرسانی واژه‌نامه ناموفق بود", - "glossaries.toast.errorDelete": "حذف واژه‌نامه ناموفق بود", - "glossaries.dialog.title": "واژه‌نامه جدید", - "glossaries.dialog.description": "یک واژه‌نامه برای ترجمه‌های خود بسازید", - "glossaries.dialog.nameLabel": "نام", - "glossaries.dialog.namePlaceholder": "واژه‌نامه من", - "glossaries.dialog.tabTemplates": "قالب‌ها", - "glossaries.dialog.tabFile": "فایل", - "glossaries.dialog.tabManual": "دستی", - "glossaries.dialog.cancel": "انصراف", - "glossaries.dialog.creating": "در حال ایجاد…", - "glossaries.dialog.importing": "در حال وارد کردن…", - "glossaries.dialog.importBtn": "وارد کردن", - "glossaries.dialog.selectPrompt": "انتخاب", - "glossaries.dialog.createBtn": "ایجاد", - "glossaries.dialog.createEmpty": "ایجاد خالی", - "glossaries.dialog.terms": "اصطلاحات", - "glossaries.dialog.templatesDesc": "یک قالب از پیش تعریف‌شده انتخاب کنید", - "glossaries.dialog.templatesEmpty": "قالبی موجود نیست", - "glossaries.dialog.dropTitle": "یک فایل CSV را اینجا بکشید", - "glossaries.dialog.dropOr": "یا", - "glossaries.dialog.dropFormats": "CSV, TSV, TXT", - "glossaries.termEditor.addTerm": "افزودن اصطلاح", - "glossaries.termEditor.maxReached": "حداکثر {max} اصطلاح برای هر واژه‌نامه رسیده است.", - "glossaries.dialog.formatTitle": "فرمت", - "glossaries.dialog.formatDesc": "مبدأ،مقصد (یکی در هر خط)", - "glossaries.dialog.formatNote": "خط اول در صورت شناسایی سرستون نادیده گرفته می‌شود", - "glossaries.dialog.errorFormat": "فرمت پشتیبانی نمی‌شود", - "glossaries.dialog.errorSize": "فایل بیش از حد بزرگ است", - "glossaries.dialog.errorEmpty": "فایل خالی", - "glossaries.dialog.errorRead": "خطای خواندن", - "glossaries.dialog.parsing": "در حال تجزیه…", - "glossaries.dialog.termsImported": "اصطلاح وارد شد", - "glossaries.dialog.changeFile": "تغییر فایل", - "glossaries.dialog.retry": "تلاش مجدد", - "glossaries.edit.title": "Modifier le glossaire", - "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", - "glossaries.edit.nameLabel": "Nom du glossaire", - "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", - "glossaries.edit.sourceLang": "Langue source", - "glossaries.edit.targetLang": "Langue cible", - "glossaries.edit.termsLabel": "Termes ({count} valides)", - "glossaries.edit.exportCsv": "Exporter CSV", - "glossaries.edit.importCsv": "Importer CSV", - "glossaries.edit.cancel": "Annuler", - "glossaries.edit.saving": "Enregistrement...", - "glossaries.edit.saveChanges": "Enregistrer les modifications", - "glossaries.edit.importFailedTitle": "Échec de l'importation", - "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", - "glossaries.edit.importSuccessTitle": "Importation réussie", - "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", - "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", - "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", - "glossaries.delete.title": "Supprimer le glossaire", - "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", - "glossaries.delete.warning": "Cette action est irréversible", - "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", - "glossaries.delete.cancel": "Annuler", - "glossaries.delete.deleting": "Suppression...", - "glossaries.delete.deleteBtn": "Supprimer", - "glossaries.upgrade.title": "Glossaires", - "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", - "glossaries.upgrade.feature1": "Créez plusieurs glossaires", - "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", - "glossaries.upgrade.feature3": "Importez/exportez via CSV", - "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", - "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", - "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", - "glossaries.upgrade.proLabel": "Pro", - "glossaries.upgrade.upgradeBtn": "Passer à Pro", - "glossaries.loading": "Chargement...", - "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", - "glossaries.howItWorks.step1Title": "Configurez ici", - "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", - "glossaries.howItWorks.step2Title": "Activez dans Traduire", - "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", - "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", - "glossaries.howItWorks.goToTranslate": "Aller à Traduire", - "glossaries.status.unsaved": "Non enregistré", - "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", - "glossaries.status.inactive": "Inactif", - "glossaries.instructions.whatForBold": "À quoi ça sert ?", - "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", - "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", - "glossaries.instructions.charCount": "{count} caractères", - "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", - "glossaries.instructions.clearAll": "Tout effacer", - "glossaries.instructions.saving": "Enregistrement…", - "glossaries.instructions.saved": "Enregistré", - "glossaries.presets.whatForBold": "À quoi ça sert ?", - "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", - "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", - "glossaries.presets.creating": "Création…", - "glossaries.presets.alreadyImported": "Déjà importé", - "glossaries.presets.it.title": "IT / Logiciel", - "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", - "glossaries.presets.legal.title": "Juridique / Contrats", - "glossaries.presets.legal.desc": "Droit des affaires, contentieux", - "glossaries.presets.medical.title": "Médical / Santé", - "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", - "glossaries.presets.finance.title": "Finance / Comptabilité", - "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", - "glossaries.presets.marketing.title": "Marketing / Publicité", - "glossaries.presets.marketing.desc": "Digital, branding, analytics", - "glossaries.presets.hr.title": "RH / Ressources Humaines", - "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", - "glossaries.presets.scientific.title": "Scientifique / Recherche", - "glossaries.presets.scientific.desc": "Publications, thèses, articles", - "glossaries.presets.ecommerce.title": "E-commerce / Vente", - "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", - "glossaries.grid.title": "Vos", - "glossaries.grid.titleHighlight": "glossaires", - "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", - "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", - "glossaries.grid.activeTranslation": "Traduction active :", - "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", - "glossaries.badge.compatible": "Compatible", - "glossaries.badge.otherTarget": "Autre cible", - "glossaries.card.editTerms": "Modifier les termes", - "glossaries.card.created": "ایجاد شد", - "glossaries.card.term": "اصطلاح", - "glossaries.card.delete": "Supprimer", - "glossaries.grid.searchPlaceholder": "Search a glossary…", - "glossaries.grid.noResults": "No results for this search.", - "glossaries.detail.backToList": "Back to glossaries", - "glossaries.detail.save": "Save", - "glossaries.detail.savedTitle": "Saved", - "glossaries.detail.savedDesc": "The glossary has been updated.", - "glossaries.detail.settingsTitle": "Settings", - "glossaries.detail.sourceLang": "Source language", - "glossaries.detail.targetLang": "Target language", - "glossaries.detail.termsTitle": "Terms", - "glossaries.detail.terms": "terms", - "glossaries.detail.searchTerms": "Filter…", - "glossaries.detail.noTerms": "No terms yet.", - "glossaries.detail.addFirstTerm": "Add the first term", - "glossaries.detail.addTerm": "Add a term", - "glossaries.detail.maxReached": "Maximum limit reached", - "glossaries.detail.source": "Source", - "glossaries.detail.target": "Target", - "glossaries.detail.sourcePlaceholder": "source term", - "glossaries.detail.targetPlaceholder": "target term", - "glossaries.detail.csvTitle": "CSV", - "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", - "glossaries.detail.export": "Export", - "glossaries.detail.import": "Import", - "glossaries.detail.dangerTitle": "Danger zone", - "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", - "glossaries.detail.deleteGlossary": "Delete this glossary", - "glossaries.detail.confirmDelete": "Confirm deletion?", - "glossaries.detail.confirm": "Confirm", - "glossaries.detail.cancel": "Cancel", - "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", - "glossaries.detail.sourceLocked": "fixed", - "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", - "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", - "glossaries.detail.notFoundTitle": "Glossary not found", - "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", - "glossaries.detail.maxTermsTitle": "Limit reached", - "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", - "glossaries.detail.importEmptyTitle": "Empty file", - "glossaries.detail.importEmptyDesc": "No terms detected in this file.", - "glossaries.detail.importedTitle": "Imported", - "glossaries.detail.importedDesc": "{count} terms imported.", - "glossaries.detail.importErrorTitle": "Read error", - "glossaries.detail.importErrorDesc": "Unable to read the file.", - "apiKeys.webhook.title": "Intégration Webhook", - "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", - "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", - "apiKeys.webhook.codeParam": "webhook_url", - "translate.mode.label": "Mode de traduction", - "translate.mode.classic": "Classique", - "translate.mode.classicDesc": "Rapide", - "translate.mode.proLlm": "Pro LLM", - "translate.mode.proLlmDesc": "Contextuel", - "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", - "translate.mode.upgradeLink": "Passer à Pro", - "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", - - // ── Pricing page ── - "pricing.nav.back": "بازگشت", - "pricing.nav.home": "خانه", - "pricing.nav.mySubscription": "اشتراک من", - - "pricing.header.badge": "مدل‌های هوش مصنوعی به‌روزرسانی شدند — مارس ۲۰۲۶", - "pricing.header.title": "طرحی برای هر نیازی", - "pricing.header.subtitle": "اسناد Word، Excel و PowerPoint خود را با حفظ قالب‌بندی اصلی ترجمه کنید. بدون نیاز به کلید API.", - "pricing.billing.monthly": "ماهانه", - "pricing.billing.yearly": "سالانه", - - "pricing.plans.free.name": "رایگان", - "pricing.plans.starter.name": "مبتدی", - "pricing.plans.pro.name": "حرفه‌ای", - "pricing.plans.business.name": "سازمانی", - "pricing.plans.enterprise.name": "شرکتی", - - "pricing.plans.free.description": "مناسب برای آشنایی با برنامه", - "pricing.plans.starter.description": "برای افراد و پروژه‌های کوچک", - "pricing.plans.pro.description": "برای متخصصان و تیم‌های در حال رشد", - "pricing.plans.business.description": "برای تیم‌ها و سازمان‌ها", - "pricing.plans.enterprise.description": "راه‌حل‌های سفارشی برای سازمان‌های بزرگ", - - "pricing.plans.pro.highlight": "محبوب‌ترین", - "pricing.plans.pro.badge": "محبوب", - "pricing.plans.enterprise.badge": "درخواستی", - - "pricing.plans.free.feat1": "۵ سند / ماه", - "pricing.plans.free.feat2": "تا ۱۵ صفحه برای هر سند", - "pricing.plans.free.feat3": "Google Translation شامل", - "pricing.plans.free.feat4": "تمام زبان‌ها (۱۳۰+)", - "pricing.plans.free.feat5": "پشتیبانی انجمن", - - "pricing.plans.starter.feat1": "۵۰ سند / ماه", - "pricing.plans.starter.feat2": "تا ۵۰ صفحه برای هر سند", - "pricing.plans.starter.feat3": "Google Translation + DeepL", - "pricing.plans.starter.feat4": "فایل‌ها تا ۱۰ مگابایت", - "pricing.plans.starter.feat5": "پشتیبانی ایمیل", - "pricing.plans.starter.feat6": "تاریخچه ۳۰ روزه", - - "pricing.plans.pro.feat1": "۲۰۰ سند / ماه", - "pricing.plans.pro.feat2": "تا ۲۰۰ صفحه برای هر سند", - "pricing.plans.pro.feat3": "ترجمه هوش مصنوعی Essential", - "pricing.plans.pro.feat4": "Google Translation + DeepL", - "pricing.plans.pro.feat5": "فایل‌ها تا ۲۵ مگابایت", - "pricing.plans.pro.feat6": "واژه‌نامه‌های سفارشی", - "pricing.plans.pro.feat7": "پشتیبانی اولویت‌دار", - "pricing.plans.pro.feat8": "تاریخچه ۹۰ روزه", - - "pricing.plans.business.feat1": "۱,۰۰۰ سند / ماه", - "pricing.plans.business.feat2": "تا ۵۰۰ صفحه برای هر سند", - "pricing.plans.business.feat3": "هوش مصنوعی پایه + پیشرفته (Claude Haiku)", - "pricing.plans.business.feat4": "تمام ارائه‌دهنده‌های ترجمه", - "pricing.plans.business.feat5": "فایل‌ها تا ۵۰ مگابایت", - "pricing.plans.business.feat6": "دسترسی API (۱۰,۰۰۰ فراخوان/ماه)", - "pricing.plans.business.feat7": "وب‌هوک اعلان", - "pricing.plans.business.feat8": "پشتیبانی اختصاصی", - "pricing.plans.business.feat9": "تاریخچه ۱ ساله", - "pricing.plans.business.feat10": "تحلیل پیشرفته", - - "pricing.plans.enterprise.feat1": "اسناد نامحدود", - "pricing.plans.enterprise.feat2": "تمام مدل‌های هوش مصنوعی (GPT-5, Claude Opus 4.6…)", - "pricing.plans.enterprise.feat3": "استقرار محلی یا ابری اختصاصی", - "pricing.plans.enterprise.feat4": "SLA 99.9% تضمین‌شده", - "pricing.plans.enterprise.feat5": "پشتیبانی اختصاصی ۲۴/۷", - "pricing.plans.enterprise.feat6": "برند سفارشی", - "pricing.plans.enterprise.feat7": "تیم‌های نامحدود", - "pricing.plans.enterprise.feat8": "یکپارچه‌سازی سفارشی", - - "pricing.card.onRequest": "درخواستی", - "pricing.card.free": "رایگان", - "pricing.card.perMonth": "/ماه", - "pricing.card.billedYearly": "{price} € / سال صورتحساب", - "pricing.card.documents": "اسناد", - "pricing.card.pagesMax": "حداکثر صفحات", - "pricing.card.aiTranslation": "ترجمه هوش مصنوعی", - "pricing.card.unlimited": "نامحدود", - "pricing.card.perMonthStat": "/ ماه", - "pricing.card.perDoc": "ص / سند", - "pricing.card.aiEssential": "پایه", - "pricing.card.aiEssentialPremium": "پایه + پیشرفته", - "pricing.card.aiCustom": "سفارشی", - "pricing.card.myPlan": "طرح من", - "pricing.card.managePlan": "مدیریت طرح من", - "pricing.card.startFree": "رایگان شروع کنید", - "pricing.card.contactUs": "تماس با ما", - "pricing.card.choosePlan": "انتخاب این طرح", - "pricing.card.processing": "در حال پردازش…", - - "pricing.comparison.title": "مقایسه تفصیلی", - "pricing.comparison.subtitle": "همه موارد شامل هر طرح", - "pricing.comparison.feature": "ویژگی", - "pricing.comparison.docsPerMonth": "اسناد / ماه", - "pricing.comparison.pagesMaxPerDoc": "حداکثر صفحات / سند", - "pricing.comparison.maxFileSize": "حداکثر حجم فایل", - "pricing.comparison.googleTranslation": "Google Translation", - "pricing.comparison.deepl": "DeepL", - "pricing.comparison.aiEssential": "ترجمه هوش مصنوعی پایه", - "pricing.comparison.aiPremium": "ترجمه هوش مصنوعی پیشرفته", - "pricing.comparison.apiAccess": "دسترسی API", - "pricing.comparison.priorityProcessing": "پردازش اولویت‌دار", - "pricing.comparison.support": "پشتیبانی", - "pricing.comparison.support.community": "انجمن", - "pricing.comparison.support.email": "ایمیل", - "pricing.comparison.support.priority": "اولویت‌دار", - "pricing.comparison.support.dedicated": "اختصاصی", - "pricing.comparison.mb": "مگابایت", - - "pricing.credits.title": "اعتبارات اضافی", - "pricing.credits.subtitle": "بیشتر نیاز دارید؟ اعتبار تکی بخرید، بدون اشتراک.", - "pricing.credits.perPage": "۱ اعتبار = ۱ صفحه ترجمه‌شده.", - "pricing.credits.bestValue": "بهترین ارزش", - "pricing.credits.unit": "اعتبار", - "pricing.credits.centsPerCredit": "سنت / اعتبار", - "pricing.credits.buy": "خرید", - - "pricing.trust.encryption.title": "رمزنگاری سرتاسری", - "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 در حالت استراحت", - "pricing.trust.languages.title": "۱۳۰+ زبان", - "pricing.trust.languages.sub": "شامل عربی، فارسی، عبری (RTL)", - "pricing.trust.parallel.title": "پردازش موازی", - "pricing.trust.parallel.sub": "هوش مصنوعی چندنخی فوق‌سریع", - "pricing.trust.availability.title": "۲۴/۷ در دسترس", - "pricing.trust.availability.sub": "۹۹.۹٪ زمان فعالیت تضمین‌شده", - - "pricing.aiModels.title": "مدل‌های هوش مصنوعی ما — مارس ۲۰۲۶", - "pricing.aiModels.essential.title": "ترجمه هوش مصنوعی پایه", - "pricing.aiModels.essential.plan": "طرح حرفه‌ای", - "pricing.aiModels.essential.descPrefix": "مبتنی بر", - "pricing.aiModels.essential.descSuffix": "— مقرون‌به‌صرفه‌ترین مدل هوش مصنوعی سال ۲۰۲۶. کیفیت قابل مقایسه با مدل‌های پیشرو با کسر هزینه.", - "pricing.aiModels.essential.modelName": "مدل هوش مصنوعی Essential", - "pricing.aiModels.essential.context": "۱۶۳هزار توکن زمینه", - "pricing.aiModels.essential.value": "ارزش عالی نسبت به قیمت", - "pricing.aiModels.premium.title": "ترجمه هوش مصنوعی پیشرفته", - "pricing.aiModels.premium.plan": "طرح سازمانی", - "pricing.aiModels.premium.descPrefix": "مبتنی بر", - "pricing.aiModels.premium.descSuffix": "توسط Anthropic — دقیق در اسناد حقوقی، پزشکی و فنی پیچیده.", - "pricing.aiModels.premium.context": "۲۰۰هزار توکن زمینه", - "pricing.aiModels.premium.precision": "بالاترین دقت", - - "pricing.faq.title": "سوالات متداول", - "pricing.faq.q1": "آیا می‌توانم طرح را هر زمان بخواهم تغییر دهم؟", - "pricing.faq.a1": "بله. ارتقا فوری و به‌نسبت است. تنزل در پایان دوره جاری اعمال می‌شود.", - "pricing.faq.q2": "\"ترجمه هوش مصنوعی پایه\" چیست؟", - "pricing.faq.a2": "این موتور هوش مصنوعی ماست. زمینه اسناد شما را درک می‌کند، طرح‌بندی را حفظ می‌کند و اصطلاحات فنی را بسیار بهتر از ترجمه کلاسیک مدیریت می‌کند.", - "pricing.faq.q3": "تفاوت هوش مصنوعی پایه و پیشرفته چیست؟", - "pricing.faq.a3": "هوش مصنوعی Essential از یک مدل بهینه‌شده استفاده می‌کند (ارزش عالی برای پول). هوش مصنوعی Premium از Claude 3.5 Haiku انترپیک استفاده می‌کند که در اسناد حقوقی، پزشکی و فنی پیچیده دقیق‌تر است.", - "pricing.faq.q4": "آیا اسناد من پس از ترجمه نگهداری می‌شوند؟", - "pricing.faq.a4": "فایل‌های ترجمه‌شده طبق طرح شما در دسترس هستند (۳۰ روز مبتدی، ۹۰ روز حرفه‌ای، ۱ سال سازمانی). آنها در حالت استراحت و هنگام انتقال رمزنگاری می‌شوند.", - "pricing.faq.q5": "اگر از سهمیه ماهانه خود فراتر رویم چه می‌شود؟", - "pricing.faq.a5": "می‌توانید اعتبار اضافی تکی بخرید یا طرح خود را ارتقا دهید. در ۸۰٪ مصرف به شما اطلاع داده می‌شود.", - "pricing.faq.q6": "آیا دوره آزمایشی رایگان برای طرح‌های پولی وجود دارد؟", - "pricing.faq.a6": "طرح رایگان دائمی است و نیاز به کارت اعتباری ندارد. برای طرح‌های حرفه‌ای و سازمانی، برای دوره آزمایشی ۱۴ روزه با ما تماس بگیرید.", - "pricing.faq.q7": "چه فرمت‌های فایلی پشتیبانی می‌شوند؟", - "pricing.faq.a7": "Word (.docx)، Excel (.xlsx/.xls)، PowerPoint (.pptx) و به‌زودی PDF. تمام طرح‌ها از فرمت‌های یکسان پشتیبانی می‌کنند.", - - "pricing.cta.title": "آماده شروع هستید؟", - "pricing.cta.subtitle": "رایگان شروع کنید، بدون نیاز به کارت اعتباری. هر زمان که نیاز داشتید ارتقا دهید.", - "pricing.cta.createAccount": "ایجاد حساب رایگان", - "pricing.cta.login": "ورود", - - "pricing.toast.demo": "حالت نمایشی — Stripe هنوز پیکربندی نشده. در محیط عملیاتی، برای فعال‌سازی طرح {planId} به صفحه پرداخت هدایت می‌شوید.", - "pricing.toast.networkError": "خطای شبکه. لطفاً دوباره تلاش کنید.", - "pricing.toast.paymentError": "خطا در ایجاد پرداخت.", - - // ── Register page ── - "register.title": "ایجاد حساب کاربری", - "register.subtitle": "ترجمه را رایگان شروع کنید", - "register.error.failed": "ثبت‌نام ناموفق بود", - - "register.name.label": "نام", - "register.name.placeholder": "نام شما", - "register.name.error": "نام باید حداقل ۲ کاراکتر باشد", - - "register.email.label": "آدرس ایمیل", - "register.email.placeholder": "you@example.com", - "register.email.error": "آدرس ایمیل نامعتبر", - - "register.password.label": "رمز عبور", - "register.password.error": "رمز عبور باید حداقل ۸ کاراکتر با یک حرف بزرگ، یک حرف کوچک و یک عدد باشد", - "register.password.show": "نمایش رمز عبور", - "register.password.hide": "مخفی کردن رمز عبور", - "register.password.strengthLabel": "قدرت:", - "register.password.strength.weak": "ضعیف", - "register.password.strength.medium": "متوسط", - "register.password.strength.strong": "قوی", - - "register.confirmPassword.label": "تأیید رمز عبور", - "register.confirmPassword.error": "رمزهای عبور مطابقت ندارند", - "register.confirmPassword.show": "نمایش", - "register.confirmPassword.hide": "مخفی", - - "register.submit.creating": "در حال ایجاد حساب...", - "register.submit.create": "حساب من را بساز", - "register.hasAccount": "قبلاً حساب دارید؟", - "register.login": "وارد شوید", - "register.terms.prefix": "با ایجاد حساب، شما می‌پذیرید", - "register.terms.link": "شرایط خدمات", - - - "common.loading": "در حال بارگذاری...", - "profile.header.title": "پروفایل من", - "profile.header.subtitle": "مدیریت حساب و تنظیمات شما.", - "profile.tabs.account": "حساب کاربری", - "profile.tabs.subscription": "اشتراک", - "profile.tabs.preferences": "تنظیمات", - "profile.account.user": "کاربر", - "profile.account.memberSince": "عضو از", - "profile.plan.label": "طرح", - "profile.plan.free": "رایگان", - "profile.plan.starter": "Starter", - "profile.plan.pro": "Pro", - "profile.plan.business": "Business", - "profile.plan.enterprise": "Enterprise", - "profile.plan.pricePerMonth": "{price} €/ماه", - "profile.subscription.canceling": "در حال لغو", - "profile.subscription.active": "فعال", - "profile.subscription.unknown": "نامشخص", - "profile.subscription.accessUntil": "دسترسی تا", - "profile.subscription.renewalOn": "تمدید در", - "profile.subscription.upgradePlan": "ارتقا به طرح پولی", - "profile.subscription.changePlan": "تغییر طرح", - "profile.subscription.manageBilling": "مدیریت صورتحساب", - "profile.subscription.billingUnavailable": "پورتال صورتحساب در دسترس نیست.", - "profile.subscription.billingError": "خطا در دسترسی به پورتال صورتحساب.", - "profile.subscription.cancelSuccess": "اشتراک لغو شد. تا پایان دوره فعلی به خدمات دسترسی خواهید داشت.", - "profile.subscription.cancelError": "خطا هنگام لغو.", - "profile.subscription.networkError": "خطای شبکه.", - "profile.usage.title": "مصرف این ماه", - "profile.usage.resetOn": "بازنشانی در", - "profile.usage.documents": "اسناد", - "profile.usage.pages": "صفحات", - "profile.usage.extraCredits": "اعتبار اضافی", - "profile.usage.extraCreditsPlural": "اعتبارهای اضافی", - "profile.usage.quotaReached": "سهمیه تمام شده", - "profile.usage.quotaReachedDesc": "برای ادامه، به طرح بالاتر ارتقا دهید.", - "profile.usage.unlockMore": "با طرح پولی ترجمه‌های بیشتری داشته باشید.", - "profile.usage.viewPlans": "مشاهده طرح‌ها", - "profile.usage.includedInPlan": "شامل طرح شما", - "profile.danger.title": "منطقه خطر", - "profile.danger.description": "لغو در پایان دوره فعلی اعمال می‌شود. تا آن تاریخ به خدمات خود دسترسی خواهید داشت.", - "profile.danger.confirm": "مطمئن هستید؟ این عمل قابل برگشت نیست.", - "profile.danger.confirmCancel": "تأیید لغو", - "profile.danger.cancelSubscription": "لغو اشتراک من", - "profile.danger.keep": "خیر، نگه دار", - "profile.prefs.interfaceLang": "زبان رابط کاربری", - "profile.prefs.interfaceLangDesc": "زبان به‌طور خودکار بر اساس مرورگر شما شناسایی می‌شود. می‌توانید آن را به‌صورت دستی تغییر دهید.", - "profile.prefs.defaultTargetLang": "زبان هدف پیش‌فرض", - "profile.prefs.selectLanguage": "انتخاب زبان", - "profile.prefs.defaultTargetLangDesc": "این زبان برای ترجمه‌های شما از پیش انتخاب خواهد شد.", - "profile.prefs.save": "ذخیره", - "profile.prefs.theme": "پوسته", - "profile.prefs.themeDesc": "ظاهر رابط کاربری را انتخاب کنید", - "profile.prefs.cache": "حافظه پنهان", - "profile.prefs.cacheDesc": "پاک کردن حافظه پنهان محلی ممکن است برخی مشکلات نمایش را برطرف کند.", - "profile.prefs.clearing": "در حال پاک کردن...", - "profile.prefs.clearCache": "پاک کردن حافظه پنهان", - "settings.title": "تنظیمات", - "settings.subtitle": "پیکربندی عمومی برنامه", - "settings.formats.title": "فرمت‌های پشتیبانی شده", - "settings.formats.subtitle": "انواع سند قابل ترجمه", - "settings.formats.formulas": "فرمول‌ها", - "settings.formats.styles": "سبک‌ها", - "settings.formats.images": "تصاویر", - "settings.formats.headers": "سرصفحه‌ها", - "settings.formats.tables": "جداول", - "settings.formats.slides": "اسلایدها", - "settings.formats.notes": "یادداشت‌ها", - "settings.cache.title": "حافظه پنهان", - "settings.cache.desc": "پاک کردن حافظه پنهان محلی ممکن است برخی مشکلات نمایش را برطرف کند.", - "settings.cache.clearing": "در حال پاک کردن...", - "settings.cache.clear": "پاک کردن حافظه پنهان", - "services.title": "ارائه‌دهندگان ترجمه", - "services.subtitle": "ارائه‌دهندگان توسط مدیر پیکربندی شده‌اند. می‌توانید ببینید کدام‌یک برای حساب شما فعال است.", - "services.loading": "در حال بارگذاری ارائه‌دهندگان...", - "services.noProviders": "در حال حاضر هیچ ارائه‌دهنده‌ای پیکربندی نشده. با مدیر تماس بگیرید.", - "services.classic": "ترجمه کلاسیک", - "services.llmPro": "LLM · مبتنی بر زمینه (Pro)", - "services.available": "در دسترس", - "services.model": "مدل", - "services.adminOnly.title": "پیکربندی ارائه‌دهنده فقط برای مدیر", - "services.adminOnly.desc": "کلیدهای API، انتخاب مدل و فعال‌سازی ارائه‌دهنده منحصراً توسط مدیر در پنل مدیریت انجام می‌شود. شما هرگز نیازی به وارد کردن کلید API ندارید.", - "apiKeys.title": "کلیدهای API", - "apiKeys.subtitle": "مدیریت کلیدهای API برای دسترسی برنامه‌نویسی به API ترجمه.", - "apiKeys.loading": "در حال بارگذاری...", - "apiKeys.sectionTitle": "API و خودکارسازی", - "apiKeys.sectionDesc": "تولید و مدیریت کلیدهای API برای گردش‌کار خودکارسازی", - "apiKeys.keysUsed": "{total} از {max} کلید استفاده شده", - "apiKeys.maxReached": "حداکثر کلیدها استفاده شده. یک کلید را لغو کنید تا کلید جدیدی بسازید.", - "apiKeys.canGenerate": "می‌توانید {count} کلید دیگر بسازید", - "apiKeys.canGeneratePlural": "می‌توانید {count} کلید دیگر بسازید", - "apiKeys.generateNew": "تولید کلید جدید", - "apiKeys.keyRevoked": "کلید لغو شد", - "apiKeys.keyRevokedDesc": "کلید API با موفقیت لغو شد.", - "apiKeys.keyNotFound": "کلید یافت نشد", - "apiKeys.keyNotFoundDesc": "کلید API دیگر وجود ندارد. ممکن است قبلاً لغو شده باشد.", - "apiKeys.error": "خطا", - "apiKeys.revokeError": "لغو کلید API ناموفق بود. لطفاً دوباره تلاش کنید.", - "apiKeys.limitReached": "محدودیت تکمیل شد", - "apiKeys.limitReachedDesc": "شما به حداکثر ۱۰ کلید API رسیده‌اید. یک کلید موجود را لغو کنید تا کلید جدیدی بسازید.", - "apiKeys.proRequired": "نیاز به ویژگی Pro", - "apiKeys.proRequiredDesc": "کلیدهای API یک ویژگی Pro هستند. لطفاً حساب خود را ارتقا دهید.", - "apiKeys.generateError": "تولید کلید API ناموفق بود. لطفاً دوباره تلاش کنید.", - "apiKeys.upgrade.title": "کلیدهای API", - "apiKeys.upgrade.subtitle": "ترجمه‌های خود را با دسترسی API خودکار کنید", - "apiKeys.upgrade.feat1": "تولید کلیدهای API نامحدود", - "apiKeys.upgrade.feat2": "خودکارسازی ترجمه اسناد", - "apiKeys.upgrade.feat3": "اعلان‌های Webhook", - "apiKeys.upgrade.feat4": "حالت‌های ترجمه LLM", - "apiKeys.upgrade.proFeature": "کلیدهای API یک ویژگی {pro} هستند. ارتقا دهید تا خودکارسازی API فعال شود.", - "apiKeys.upgrade.pro": "Pro", - "apiKeys.upgrade.cta": "ارتقا به Pro", - "apiKeys.dialog.maxTitle": "حداکثر کلیدها تکمیل شد", - "apiKeys.dialog.maxDesc": "شما به حداکثر ۱۰ کلید API رسیده‌اید. لطفاً قبل از تولید کلید جدید، یک کلید موجود را لغو کنید.", - "apiKeys.dialog.close": "بستن", - "apiKeys.dialog.generated": "کلید API تولید شد!", - "apiKeys.dialog.generatedDesc": "کلید API جدید شما ایجاد شد. اکنون آن را کپی کنید - دیگر نمایش داده نخواهد شد.", - "apiKeys.dialog.important": "مهم:", - "apiKeys.dialog.importantDesc": "این تنها باری است که این کلید را می‌بینید. آن را در جای امن نگه دارید.", - "apiKeys.dialog.apiKey": "کلید API", - "apiKeys.dialog.name": "نام:", - "apiKeys.dialog.done": "انجام شد", - "apiKeys.dialog.copied": "کلید را کپی کردم", - "apiKeys.dialog.generateTitle": "تولید کلید API جدید", - "apiKeys.dialog.generateDesc": "ایجاد کلید API جدید برای دسترسی برنامه‌نویسی به API ترجمه.", - "apiKeys.dialog.keyName": "نام کلید (اختیاری)", - "apiKeys.dialog.keyNamePlaceholder": "مثلاً: تولید، آزمایش", - "apiKeys.dialog.keyNameHint": "نامی توصیفی برای کمک به شناسایی این کلید در آینده.", - "apiKeys.dialog.nameTooLong": "نام باید {max} کاراکتر یا کمتر باشد", - "apiKeys.dialog.nameInvalid": "نام فقط می‌تواند شامل حروف، اعداد، فاصله، خط تیره و زیرخط باشد", - "apiKeys.dialog.cancel": "لغو", - "apiKeys.dialog.generating": "در حال تولید...", - "apiKeys.dialog.generate": "تولید کلید", - "apiKeys.table.name": "نام", - "apiKeys.table.prefix": "پیشوند", - "apiKeys.table.created": "تاریخ ایجاد", - "apiKeys.table.lastUsed": "آخرین استفاده", - "apiKeys.table.never": "هرگز", - "apiKeys.table.actions": "عملیات", - "apiKeys.table.revoke": "لغو", - "apiKeys.table.copyPrefix": "کپی پیشوند کلید", - "apiKeys.table.revokeKey": "لغو کلید", - "apiKeys.revokeDialog.title": "لغو کلید API", - "apiKeys.revokeDialog.desc": "آیا مطمئنید می‌خواهید کلید \"{name}\" را لغو کنید؟ این عمل قابل برگشت نیست.", - "apiKeys.revokeDialog.confirm": "بله، لغو کن", - "apiKeys.revokeDialog.cancel": "لغو", - "context.proTitle": "ویژگی Pro", - "context.proDesc": "زمینه و واژه‌نامه‌های حرفه‌ای با طرح‌های Pro، Business و Enterprise در دسترس هستند. آنها از طریق دستورالعمل‌ها و واژگان خاص حوزه شما، ترجمه‌های دقیق‌تری ارائه می‌دهند.", - "context.viewPlans": "مشاهده طرح‌ها", - "context.title": "زمینه و واژه‌نامه", - "context.subtitle": "با دستورالعمل‌ها و واژگان خاص حوزه خود، کیفیت ترجمه را بهبود ببخشید.", - "context.presets.title": "واژه‌نامه‌های حرفه‌ای", - "context.presets.desc": "بارگذاری واژه‌نامه کامل با دستورالعمل‌ها و اصطلاحات تخصصی", - "context.instructions.title": "دستورالعمل‌های زمینه", - "context.instructions.desc": "دستورالعمل‌هایی که هوش مصنوعی حین ترجمه پیروی می‌کند", - "context.instructions.placeholder": "مثال: شما اسناد فنی HVAC را ترجمه می‌کنید. از اصطلاحات دقیق مهندسی استفاده کنید...", - "context.glossary.title": "واژه‌نامه فنی", - "context.glossary.desc": "فرمت: source=target (یکی در هر خط). واژه‌نامه‌های بارگذاری‌شده از طریق پیش‌تنظیم قابل ویرایش هستند.", - "context.glossary.terms": "اصطلاح در واژه‌نامه", - "context.clearAll": "پاک کردن همه", - "context.saving": "در حال ذخیره...", - "context.save": "ذخیره", - "translate.glossary.title": "واژه‌نامه", - "translate.glossary.select": "انتخاب واژه‌نامه", - "translate.glossary.none": "هیچکدام", - "translate.glossary.terms": "واژه", - "translate.glossary.proOnly": "ارتقا به Pro برای استفاده از واژه‌نامه", - "translate.glossary.myGlossaries": "واژه‌نامه‌های من", - "translate.glossary.fromTemplate": "ایجاد از قالب", - "translate.glossary.noGlossaryForPair": "واژه‌نامه‌ای برای", - "translate.glossary.noGlossaries": "واژه‌نامه‌ای نیست", - "translate.glossary.loading": "در حال بارگذاری...", - "translate.glossary.classicMode": "موتور خنثی بدون واژه‌نامه (فقط هوش مصنوعی)", - "translate.glossary.selectPlaceholder": "واژه‌نامه‌ای انتخاب کنید...", - "translate.glossary.multilingual": "چندزبانه", - "translate.glossary.noGlossaryAvailable": "واژه‌نامه‌ای در دسترس نیست", - "translate.glossary.filterByLang": "فیلتر بر اساس زبان", - "translate.glossary.active": "فعال", - "translate.glossary.inactive": "غیرفعال", - "translate.glossary.availableTemplates": "قالب‌های موجود", - "translate.glossary.importing": "در حال وارد کردن...", - "translate.glossary.imported": "(وارد شده)", - "translate.glossary.noGlossaryForSource": "واژه‌نامه یا قالبی برای زبان مبدأ وجود ندارد", - "translate.glossary.createGlossary": "ایجاد واژه‌نامه", - "translate.glossary.showAll": "نمایش همه واژه‌نامه‌ها", - "translate.glossary.activePreview": "پیش‌نمایش تطبیق‌های فعال:", - "translate.glossary.total": "مجموع", - "translate.glossary.moreTerms": "واژه‌های بیشتر", - "translate.glossary.noTerms": "واژه‌ای در این واژه‌نامه وجود ندارد.", - "translate.glossary.sourceTerm": "واژه مبدأ", - "translate.glossary.translation": "ترجمه", - "translate.glossary.addTerm": "افزودن واژه", - "translate.glossary.disabledMode": "موتور خنثی بدون واژه‌نامه اعمال شده", - "translate.glossary.addTermError": "خطا در افزودن واژه", - "translate.glossary.networkError": "خطای شبکه", - "translate.glossary.importFailed": "وارد کردن ناموفق ({status})", - "translate.glossary.helpText": "واژه‌نامه ترجمه دقیق واژه‌ها را اجباری می‌کند. واژه‌نامه‌ای انتخاب کنید که زبان مبدأ آن با زبان اصلی سند شما مطابقت داشته باشد.", - "translate.glossary.sourceWarning": "هشدار: این واژه‌نامه از زبان مبدأ استفاده می‌کند", - "translate.glossary.sourceWarningBut": "اما سند شما پیکربندی شده به", - "translate.glossary.targetWarning": "عدم سازگاری هدف: این واژه‌نامه برای ترجمه به", - "translate.glossary.targetWarningBut": "اما هدف سند شما", - "translate.glossary.targetWarningEnd": "واژه‌ها ممکن است مرتبط نباشند.", - "context.presets.createGlossary": "ایجاد واژه‌نامه", - "context.presets.created": "واژه‌نامه ایجاد شد", - "context.presets.createdDesc": "واژه‌نامه \"{name}\" با {count} واژه ایجاد شد.", - "context.presets.hint": "روی یک پیش‌تنظیم کلیک کنید تا واژه‌نامه‌ای با اصطلاحات تخصصی ایجاد شود. واژه‌نامه‌های خود را در بخش واژه‌نامه‌ها مدیریت کنید.", - "context.glossary.manage": "مدیریت واژه‌نامه‌ها", - "context.saved": "ذخیره شد", - "context.savedDesc": "دستورالعمل‌های زمینه شما ذخیره شد.", - "admin.login.title": "مدیریت", - "admin.login.required": "ورود لازم است", - "admin.login.password": "رمز عبور مدیر", - "admin.login.connecting": "در حال اتصال...", - "admin.login.access": "دسترسی به پنل مدیریت", - "admin.login.restricted": "مختص مدیران", - "admin.layout.checking": "در حال تأیید احراز هویت...", - "admin.dashboard.title": "داشبورد مدیریت", - "admin.dashboard.subtitle": "پنل کنترل مدیر", - "admin.dashboard.refresh": "بازنشانی", - "admin.dashboard.refreshTooltip": "بازنشانی داده‌های داشبورد", - "admin.dashboard.config": "پیکربندی سیستم", - "admin.dashboard.maxFileSize": "حداکثر حجم فایل:", - "admin.dashboard.translationService": "سرویس ترجمه:", - "admin.dashboard.formats": "فرمت‌ها:", - "admin.nav.dashboard": "Dashboard", - "admin.nav.users": "کاربران", - "admin.nav.pricing": "قیمت‌ها و Stripe", - "admin.nav.providers": "ارائه‌دهندگان", - "admin.nav.system": "سیستم", - "admin.nav.logs": "گزارش‌ها", - "admin.users.title": "مدیریت کاربران", - "admin.users.subtitle": "مشاهده و مدیریت حساب‌های کاربری", - "admin.users.planUpdated": "طرح به‌روز شد", - "admin.users.planChanged": "طرح با موفقیت به \"{plan}\" تغییر کرد.", - "admin.users.unknownError": "خطای ناشناخته", - "admin.users.error": "خطا", - "admin.users.planUpdateError": "به‌روزرسانی طرح ممکن نیست: {message}", - "admin.users.noKeys": "بدون کلید", - "admin.users.noKeysDesc": "این کاربر کلید API فعالی ندارد.", - "admin.users.keysRevoked": "کلیدها ابطال شدند", - "admin.users.keysRevokedDesc": "{count} کلید API با موفقیت ابطال شد.", - "admin.users.revokeError": "ابطال کلیدها ممکن نیست: {message}", - "admin.users.retry": "تلاش مجدد", - "admin.system.title": "سیستم", - "admin.system.subtitle": "پایش وضعیت سیستم و مدیریت منابع", - "admin.system.quotas": "سهمیه‌های ترجمه", - "admin.system.resetQuotas": "بازنشانی سهمیه‌های ماهانه", - "admin.system.resetting": "در حال بازنشانی...", - "admin.system.reset": "بازنشانی", - "admin.system.allOperational": "تمام سیستم‌ها عملیاتی هستند", - "admin.system.issuesDetected": "مشکلات سیستمی شناسایی شد", - "admin.system.waitingData": "در انتظار داده...", - "admin.system.purging": "در حال پاکسازی...", - "admin.system.clean": "پاکسازی", - "admin.system.purge": "حذف کامل", - "memento.title": "Momento را کشف کنید", - "memento.slogan": "Momento فقط یک برنامه یادداشت نیست. یک اکوسیستم هوشمند است که با استفاده از ۶ عامل هوش مصنوعی و جستجوی معنایی پیشرفته، ایده‌های شما را در زمان واقعی متصل، تحلیل و توسعه می‌دهد.", - "memento.ctaFree": "رایگان شروع کنید", - "memento.ctaMore": "بیشتر بدانید", - "common.backToHome": "بازگشت به صفحه اصلی", - "dashboard.topbar.interfaceLabel": "رابط ترجمه", - "dashboard.topbar.premiumAccess": "دسترسی ویژه", - "landing.hero.contextEngine": "ترجمه شناسایی شد: اصطلاح فنی نگهداری برای سیستم‌های تهویه...", - "landing.hero.liveAnalysis": "تحلیل زنده", - "landing.hero.termsDetected": "اصطلاح شناسایی شد", - "landing.steps.process": "فرآیند", - "landing.translate.newProject": "پروژه جدید", - "landing.translate.title": "ترجمه سند", - "landing.translate.subtitle": "فایل را وارد کنید و زبان مقصد را انتخاب کنید", - "landing.translate.sourceDocument": "سند منبع", - "landing.translate.configuration": "پیکربندی", - "landing.translate.sourceLang": "زبان منبع", - "landing.translate.targetLang": "زبان مقصد", - "landing.translate.provider": "ارائه‌دهنده", - "landing.translate.startTranslation": "شروع ترجمه", - "landing.translate.zeroRetention": "صفر نگهداری", - "landing.translate.filesDeleted": "فایل‌ها پس از پردازش حذف می‌شوند", - "landing.translate.dropHere": "اینجا بکشید و رها کنید", - "landing.translate.supportedFormats": "فایل‌های DOCX, XLSX, PPTX یا PDF پشتیبانی می‌شوند", - "landing.translate.aiAnalysis": "تحلیل AI فعال", - "landing.translate.processing": "در حال پردازش", - "landing.translate.preservingLayout": "طرح‌بندی شما حفظ می‌شود", - "layout.nav.apiAccess": "دسترسی API", - "layout.footer.terms": "شرایط", - "layout.footer.privacy": "حریم خصوصی", - "fileUploader.uploadDocument": "بارگذاری سند", - "fileUploader.uploadDesc": "فایل را بکشید و رها کنید یا کلیک کنید (Excel, Word, PowerPoint)", - "fileUploader.dropHere": "فایل خود را اینجا رها کنید…", - "fileUploader.dragAndDrop": "سند خود را اینجا بکشید و رها کنید", - "fileUploader.orClickBrowse": "یا کلیک کنید برای مرور", - "fileUploader.preview": "پیش‌نمایش", - "fileUploader.translationOptions": "گزینه‌های ترجمه", - "fileUploader.configureSettings": "تنظیمات ترجمه را پیکربندی کنید", - "fileUploader.targetLanguage": "زبان مقصد", - "fileUploader.selectLanguage": "زبان را انتخاب کنید", - "fileUploader.translationProvider": "ارائه‌دهنده ترجمه", - "fileUploader.selectProvider": "ارائه‌دهنده را انتخاب کنید", - "fileUploader.advancedOptions": "گزینه‌های پیشرفته", - "fileUploader.translateImages": "ترجمه تصاویر", - "fileUploader.translating": "در حال ترجمه…", - "fileUploader.translateDocument": "ترجمه سند", - "fileUploader.processing": "در حال پردازش…", - "fileUploader.translationError": "خطای ترجمه", - "fileUploader.translationComplete": "ترجمه کامل شد!", - "fileUploader.translationCompleteDesc": "سند شما با حفظ تمام قالب‌بندی با موفقیت ترجمه شد.", - "fileUploader.download": "بارگیری سند ترجمه‌شده", - "fileUploader.webgpuUnsupported": "WebGPU در این مرورگر پشتیبانی نمی‌شود. لطفاً از Chrome 113+ یا Edge 113+ استفاده کنید.", - "fileUploader.webllmNotLoaded": "مدل WebLLM بارگذاری نشده است. به تنظیمات > سرویس‌های ترجمه بروید تا یک مدل بارگذاری کنید.", - "fileUploader.extracting": "در حال استخراج متن از سند…", - "fileUploader.noTranslatable": "متن قابل ترجمه در سند یافت نشد", - "fileUploader.foundTexts": "{count} متن برای ترجمه یافت شد", - "fileUploader.translatingItem": "در حال ترجمه {current}/{total}: \"{preview}\"", - "fileUploader.reconstructing": "در حال بازسازی سند…", - "fileUploader.translatingLocally": "ترجمه محلی با WebLLM…", - "checkout.activating": "در حال فعال‌سازی…", - "checkout.activatingDesc": "در حال به‌روزرسانی اشتراک شما هستیم، لطفاً صبر کنید.", - "checkout.paymentConfirmed": "پرداخت تأیید شد!", - "checkout.subscriptionActivated": "اشتراک فعال شد!", - "checkout.planActivated": "پلن {plan} فعال شد!", - "checkout.redirectingToProfile": "در حال هدایت به نمایه شما…", - "checkout.paymentReceived": "پرداخت دریافت شد", - "checkout.redirecting": "در حال هدایت…", - "checkout.syncError": "خطای همگام‌سازی", - "checkout.networkError": "خطای شبکه. پرداخت شما تأیید شد — لطفاً نمایه خود را بارگیری مجدد کنید.", - "dashboard.checkoutSyncError": "خطا در همگام‌سازی پرداخت.", - "dashboard.networkRefresh": "خطای شبکه. لطفاً صفحه را تازه‌سازی کنید.", - "dashboard.continueToTranslate": "ادامه به ترجمه", - "langSelector.search": "جستجو…", - "langSelector.noResults": "بدون نتیجه", - "langSelector.source": "مبدأ", - "langSelector.target": "هدف", - "langSelector.swap": "جابجایی", - "translateComplete.highQuality": "کیفیت بالا", - "translateComplete.segments": "قطعه‌ها", - "translateComplete.characters": "نویسه‌ها", - "translateComplete.confidence": "اعتماد", - "providerTheme.deepseek.badge": "اساسی", - "providerTheme.deepseek.subBadge": "فنی و اقتصادی", - "providerTheme.deepseek.desc": "ترجمه فوق‌دقیق و اقتصادی، ایده‌آل برای اسناد فنی و کد.", - "providerTheme.openai.badge": "ویژه", - "providerTheme.openai.subBadge": "وفاداری بالا", - "providerTheme.openai.desc": "استاندارد جهانی هوش مصنوعی. حداکثر سازگاری متنی و رعایت دقیق سبک.", - "providerTheme.minimax.badge": "پیشرفته", - "providerTheme.minimax.subBadge": "عملکرد", - "providerTheme.minimax.desc": "سرعت اجرای باورنکردنی و درک عالی از ساختارهای پیچیده.", - "providerTheme.openrouter.badge": "سریع", - "providerTheme.openrouter.subBadge": "چند مدل", - "providerTheme.openrouter.desc": "دسترسی یکپارچه به بهترین مدل‌های متن‌باز بهینه‌سازی‌شده برای ترجمه.", - "providerTheme.openrouter_premium.badge": "فوق‌العاده", - "providerTheme.openrouter_premium.subBadge": "حداکثر زمینه", - "providerTheme.openrouter_premium.desc": "با کمک مدل‌های پیشرفته (GPT-4o، Claude Sonnet 4.6) برای اسناد طولانی.", - "providerTheme.zai.badge": "تخصصی", - "providerTheme.zai.subBadge": "مالی و حقوقی", - "providerTheme.zai.desc": "مدل تنظیم‌شده برای اصطلاحات تجاری سخت‌گیرانه (حقوقی، مالی).", - "providerTheme.default.badge": "مدرن", - "providerTheme.default.subBadge": "استدلال هوش مصنوعی", - "providerTheme.default.desc": "ترجمه مدل زبانی بزرگ (LLM) با تحلیل معنایی پیشرفته.", - "providerTheme.classic.google.label": "ترجمه Google", - "providerTheme.classic.google.desc": "ترجمه فوق‌سریع با پوشش بیش از 130 زبان. برای جریان‌های عمومی توصیه می‌شود.", - "providerTheme.classic.deepl.label": "DeepL Pro", - "providerTheme.classic.deepl.desc": "ترجمه با دقت بالا که به دلیل روانی و عبارات طبیعی شهرت دارد.", - "providerTheme.classic.google_cloud.label": "Google Cloud API", - "providerTheme.classic.google_cloud.desc": "موتور ابری حرفه‌ای بهینه‌سازی‌شده برای پردازش حجم زیاد اسناد.", - "providerSelector.noClassic": "مترجم استاندارد موجود نیست.", - "providerSelector.noLlm": "هیچ مدل هوش مصنوعی پیکربندی نشده است.", - "providerSelector.costOne": "هزینه: 1 اعتبار در هر صفحه", - "providerSelector.costFive": "هزینه: 5 اعتبار در هر صفحه (ضریب ویژه)", - "providerSelector.unlockContextual": "ترجمه زمینه‌ای ویژه را برای کل اسناد خود فعال کنید.", - "translate.header.processing": "در حال پردازش", - "translate.header.aiActive": "تحلیل هوش مصنوعی فعال", - "translate.header.aiActiveDesc": "چیدمان شما توسط موتور زمینه‌ای ما حفظ می‌شود.", - "translate.header.completed": "تکمیل شد", - "translate.header.completedTitle": "ترجمه تکمیل شد", - "translate.header.proSpace": "فضای Pro", - "translate.header.translateDoc": "ترجمه یک سند", - "translate.header.translateDocDesc": "چیدمان اصلی را با موتور ترجمه فوق‌دقیق ما حفظ کنید.", - "translate.upload.nativeFormat": "قالب بومی", - "translate.fileType.word": "Word (.docx)", - "translate.fileType.excel": "Excel (.xlsx)", - "translate.fileType.slides": "اسلایدها (.pptx)", - "translate.fileType.pdf": "PDF (.pdf)", - "translate.startTranslation": "شروع ترجمه", - "translate.submit": "در حال ارسال…", - "translate.chooseTargetLang": "لطفاً یک زبان مقصد انتخاب کنید", - "translate.pleaseLoadFile": "لطفاً ابتدا یک فایل بارگذاری کنید", - "translate.contextEngineActive": "موتور زمینه‌ای فعال", - "translate.phase1": "مرحله 1: مقداردهی اولیه", - "translate.phase2": "مرحله 2: بازسازی زمینه‌ای", - "translate.stat.segments": "قطعه‌ها", - "translate.stat.precision": "دقت", - "translate.stat.speedLabel": "سرعت", - "translate.stat.turbo": "توربو", - "translate.stat.time": "زمان", - "translate.complete.masterQuality": "✓ کیفیت عالی", - "translate.download": "بارگیری", - "translate.newTranslation": "+ ترجمه جدید", - "translate.failedTitle": "خطای ترجمه", - "translate.retry": "تلاش مجدد", - "translate.uploadAnother": "بارگذاری فایل دیگر", - "translate.monitor": "مانیتور هوش مصنوعی", - "translate.summary": "خلاصه", - "translate.cancelProcess": "⟳ لغو فرآیند", - "translate.layoutIntegrity": "یکپارچگی چیدمان", - "translate.secureHundred": "100% امن", - "translate.okHundred": "100% OK", - "translate.preserveLayout": "حفظ چیدمان", - "translate.preserveLayoutDesc": "حفظ چیدمان", - "translate.textOnly": "فقط متن", - "translate.textOnlyDesc": "ترجمه سریع فقط متن", - "translate.unavailableStandard": "در حالت استاندارد موجود نیست (فقط AI)", - "apiKeys.noKeysGenerated": "کلیدی تولید نشده", - "apiKeys.copied": "کپی شد!", - "services.fallback.google.label": "ترجمه Google", - "services.fallback.google.desc": "ترجمه سریع، بیش از 130 زبان", - "settings.formats.excel.name": "Excel", - "settings.formats.word.name": "Word", - "settings.formats.powerpoint.name": "PowerPoint", - "pricing.dashboard": "داشبورد", - "pricing.okSymbol": "✓", - "pricing.errSymbol": "✕", - }, -}; - -const RTL_LOCALES: ReadonlyArray = ["ar", "fa"]; - interface I18nContextValue { locale: Locale; dir: "ltr" | "rtl"; isRTL: boolean; setLocale: (locale: Locale) => void; t: (key: string, params?: TranslationParams) => string; + isLoading: boolean; } const I18nContext = createContext(null); -function interpolate( - template: string, - params?: TranslationParams, -): string { +const messageCache: Partial>> = { + en: enMessages, +}; + +function interpolate(template: string, params?: TranslationParams): string { if (!params) return template; return Object.entries(params).reduce( (acc, [k, v]) => acc.replace(new RegExp(`\\{${k}\\}`, "g"), String(v)), @@ -14104,18 +72,15 @@ function interpolate( } function detectInitialLocale(): Locale { - if (typeof window === "undefined") return "en"; - // 1. Saved preference wins + if (typeof window === "undefined") return DEFAULT_LOCALE; const saved = localStorage.getItem("locale"); if (saved && (VALID_LOCALES as readonly string[]).includes(saved)) { return saved as Locale; } - // 2. Browser language (exact match: "fr", "de", …) const primary = navigator.language.split("-")[0]; if ((VALID_LOCALES as readonly string[]).includes(primary)) { return primary as Locale; } - // 3. Check all browser languages (e.g. navigator.languages = ["fr-FR","en-US","en"]) const allLangs = navigator.languages || []; for (const lang of allLangs) { const code = lang.split("-")[0]; @@ -14123,43 +88,89 @@ function detectInitialLocale(): Locale { return code as Locale; } } - return "en"; + return DEFAULT_LOCALE; } -export function formatDate(date: Date, locale: Locale, options?: Intl.DateTimeFormatOptions): string { - const calendar = locale === "fa" ? "fa-IR-u-ca-persian" : locale === "ar" ? "ar-SA" : locale; - const defaults: Intl.DateTimeFormatOptions = { day: "numeric", month: "long", year: "numeric" }; +async function loadLocaleMessages(locale: Locale): Promise> { + if (messageCache[locale]) return messageCache[locale]; + + try { + const mod = await import(`./i18n/messages/${locale}`); + messageCache[locale] = mod.default as Record; + return messageCache[locale]; + } catch (err) { + console.warn(`Failed to load locale messages for ${locale}`, err); + messageCache[locale] = enMessages; + return enMessages; + } +} + +export function formatDate( + date: Date, + locale: Locale, + options?: Intl.DateTimeFormatOptions, +): string { + const calendar = + locale === "fa" ? "fa-IR-u-ca-persian" : locale === "ar" ? "ar-SA" : locale; + const defaults: Intl.DateTimeFormatOptions = { + day: "numeric", + month: "long", + year: "numeric", + }; return date.toLocaleDateString(calendar, { ...defaults, ...options }); } export function I18nProvider({ children }: { children: ReactNode }) { - const [locale, setLocale] = useState(detectInitialLocale); + const [locale, setLocaleState] = useState(detectInitialLocale); + const [messages, setMessages] = useState>(enMessages); + const [isLoading, setIsLoading] = useState(false); const isRTL = (RTL_LOCALES as readonly string[]).includes(locale); - const dir = isRTL ? "rtl" as const : "ltr" as const; + const dir = isRTL ? ("rtl" as const) : ("ltr" as const); useEffect(() => { document.documentElement.dir = dir; document.documentElement.lang = locale; }, [locale, dir]); - const handleSetLocale = useCallback((newLocale: Locale) => { - setLocale(newLocale); + useEffect(() => { + let cancelled = false; + if (locale === "en") { + setMessages(enMessages); + return; + } + setIsLoading(true); + loadLocaleMessages(locale).then((loaded) => { + if (!cancelled) { + setMessages(loaded); + setIsLoading(false); + } + }); + return () => { + cancelled = true; + }; + }, [locale]); + + const setLocale = useCallback((newLocale: Locale) => { + setLocaleState(newLocale); localStorage.setItem("locale", newLocale); }, []); const t = useCallback( (key: string, params?: TranslationParams): string => { - const msg = messages[locale]?.[key] || messages.en[key] || key; + const msg = messages[key] ?? enMessages[key] ?? key; return interpolate(msg, params); }, - [locale], + [messages], + ); + + const value = useMemo( + () => ({ locale, dir, isRTL, setLocale, t, isLoading }), + [locale, dir, isRTL, setLocale, t, isLoading], ); return ( - - {children} - + {children} ); } diff --git a/frontend/src/lib/i18n/messages/ar/admin.json b/frontend/src/lib/i18n/messages/ar/admin.json new file mode 100644 index 0000000..d1846c4 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/admin.json @@ -0,0 +1,48 @@ +{ + "admin.login.title": "الإدارة", + "admin.login.required": "تسجيل الدخول مطلوب", + "admin.login.password": "كلمة مرور المسؤول", + "admin.login.connecting": "جارٍ الاتصال...", + "admin.login.access": "الدخول إلى لوحة الإدارة", + "admin.login.restricted": "مخصص للمسؤولين فقط", + "admin.layout.checking": "جارٍ التحقق من المصادقة...", + "admin.dashboard.title": "لوحة تحكم المسؤول", + "admin.dashboard.subtitle": "لوحة تحكم المسؤولين", + "admin.dashboard.refresh": "تحديث", + "admin.dashboard.refreshTooltip": "تحديث بيانات لوحة التحكم", + "admin.dashboard.config": "إعدادات النظام", + "admin.dashboard.maxFileSize": "الحد الأقصى لحجم الملف:", + "admin.dashboard.translationService": "خدمة الترجمة:", + "admin.dashboard.formats": "التنسيقات:", + "admin.nav.dashboard": "Dashboard", + "admin.nav.users": "المستخدمون", + "admin.nav.pricing": "الأسعار و Stripe", + "admin.nav.providers": "المزوّدون", + "admin.nav.system": "النظام", + "admin.nav.logs": "السجلات", + "admin.users.title": "إدارة المستخدمين", + "admin.users.subtitle": "عرض حسابات المستخدمين وإدارتها", + "admin.users.planUpdated": "تم تحديث الخطة", + "admin.users.planChanged": "تم تغيير الخطة إلى \\\"{plan}\\\" بنجاح.", + "admin.users.unknownError": "خطأ غير معروف", + "admin.users.error": "خطأ", + "admin.users.planUpdateError": "تعذر تحديث الخطة: {message}", + "admin.users.noKeys": "لا توجد مفاتيح", + "admin.users.noKeysDesc": "لا يمتلك هذا المستخدم مفاتيح API نشطة.", + "admin.users.keysRevoked": "تم إلغاء المفاتيح", + "admin.users.keysRevokedDesc": "تم إلغاء {count} مفتاح API بنجاح.", + "admin.users.revokeError": "تعذر إلغاء المفاتيح: {message}", + "admin.users.retry": "إعادة المحاولة", + "admin.system.title": "النظام", + "admin.system.subtitle": "مراقبة حالة النظام وإدارة الموارد", + "admin.system.quotas": "حصص الترجمة", + "admin.system.resetQuotas": "إعادة تعيين الحصص الشهرية", + "admin.system.resetting": "جارٍ إعادة التعيين...", + "admin.system.reset": "إعادة تعيين", + "admin.system.allOperational": "جميع الأنظمة تعمل بشكل طبيعي", + "admin.system.issuesDetected": "تم اكتشاف مشاكل في النظام", + "admin.system.waitingData": "في انتظار البيانات...", + "admin.system.purging": "جارٍ الحذف...", + "admin.system.clean": "تنظيف", + "admin.system.purge": "حذف" +} diff --git a/frontend/src/lib/i18n/messages/ar/apiKeys.json b/frontend/src/lib/i18n/messages/ar/apiKeys.json new file mode 100644 index 0000000..487823c --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/apiKeys.json @@ -0,0 +1,72 @@ +{ + "apiKeys.webhook.title": "Intégration Webhook", + "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", + "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", + "apiKeys.webhook.codeParam": "webhook_url", + "apiKeys.title": "مفاتيح API", + "apiKeys.subtitle": "إدارة مفاتيح API للوصول البرمجي إلى واجهة الترجمة.", + "apiKeys.loading": "جارٍ التحميل...", + "apiKeys.sectionTitle": "API والأتمتة", + "apiKeys.sectionDesc": "إنشاء وإدارة مفاتيح API لسير عمل الأتمتة", + "apiKeys.keysUsed": "{total} من {max} مفاتيح مستخدمة", + "apiKeys.maxReached": "تم بلوغ الحد الأقصى للمفاتيح. قم بإلغاء مفتاح لإنشاء واحد جديد.", + "apiKeys.canGenerate": "يمكنك إنشاء {count} مفتاح إضافي", + "apiKeys.canGeneratePlural": "يمكنك إنشاء {count} مفاتيح إضافية", + "apiKeys.generateNew": "إنشاء مفتاح جديد", + "apiKeys.keyRevoked": "تم إلغاء المفتاح", + "apiKeys.keyRevokedDesc": "تم إلغاء مفتاح API بنجاح.", + "apiKeys.keyNotFound": "المفتاح غير موجود", + "apiKeys.keyNotFoundDesc": "مفتاح API لم يعد موجودًا. ربما تم إلغاؤه بالفعل.", + "apiKeys.error": "خطأ", + "apiKeys.revokeError": "فشل إلغاء مفتاح API. يرجى المحاولة مرة أخرى.", + "apiKeys.limitReached": "تم بلوغ الحد", + "apiKeys.limitReachedDesc": "لقد وصلت إلى الحد الأقصى وهو 10 مفاتيح API. قم بإلغاء مفتاح حالي لإنشاء واحد جديد.", + "apiKeys.proRequired": "ميزة Pro مطلوبة", + "apiKeys.proRequiredDesc": "مفاتيح API هي ميزة Pro. يرجى ترقية حسابك.", + "apiKeys.generateError": "فشل إنشاء مفتاح API. يرجى المحاولة مرة أخرى.", + "apiKeys.upgrade.title": "مفاتيح API", + "apiKeys.upgrade.subtitle": "أتمتة ترجماتك مع وصول API", + "apiKeys.upgrade.feat1": "إنشاء مفاتيح API غير محدودة", + "apiKeys.upgrade.feat2": "أتمتة ترجمة المستندات", + "apiKeys.upgrade.feat3": "إشعارات Webhook", + "apiKeys.upgrade.feat4": "أوضاع ترجمة LLM", + "apiKeys.upgrade.proFeature": "مفاتيح API هي ميزة {pro}. قم بالترقية لفتح أتمتة API.", + "apiKeys.upgrade.pro": "Pro", + "apiKeys.upgrade.cta": "الترقية إلى Pro", + "apiKeys.dialog.maxTitle": "تم بلوغ الحد الأقصى للمفاتيح", + "apiKeys.dialog.maxDesc": "لقد وصلت إلى الحد الأقصى وهو 10 مفاتيح API. يرجى إلغاء مفتاح حالي قبل إنشاء واحد جديد.", + "apiKeys.dialog.close": "إغلاق", + "apiKeys.dialog.generated": "تم إنشاء مفتاح API!", + "apiKeys.dialog.generatedDesc": "تم إنشاء مفتاح API الجديد. انسخه الآن - لن يظهر مرة أخرى.", + "apiKeys.dialog.important": "مهم:", + "apiKeys.dialog.importantDesc": "هذه هي المرة الوحيدة التي سترى فيها هذا المفتاح. احفظه في مكان آمن.", + "apiKeys.dialog.apiKey": "مفتاح API", + "apiKeys.dialog.name": "الاسم:", + "apiKeys.dialog.done": "تم", + "apiKeys.dialog.copied": "لقد نسخت المفتاح", + "apiKeys.dialog.generateTitle": "إنشاء مفتاح API جديد", + "apiKeys.dialog.generateDesc": "إنشاء مفتاح API جديد للوصول البرمجي إلى واجهة الترجمة.", + "apiKeys.dialog.keyName": "اسم المفتاح (اختياري)", + "apiKeys.dialog.keyNamePlaceholder": "مثال: الإنتاج، الاختبار", + "apiKeys.dialog.keyNameHint": "اسم وصفي لمساعدتك على التعرف على هذا المفتاح لاحقًا.", + "apiKeys.dialog.nameTooLong": "يجب ألا يتجاوز الاسم {max} حرفًا", + "apiKeys.dialog.nameInvalid": "يمكن أن يحتوي الاسم على أحرف وأرقام ومسافات وشرطات وشرطات سفلية فقط", + "apiKeys.dialog.cancel": "إلغاء", + "apiKeys.dialog.generating": "جارٍ الإنشاء...", + "apiKeys.dialog.generate": "إنشاء مفتاح", + "apiKeys.table.name": "الاسم", + "apiKeys.table.prefix": "البادئة", + "apiKeys.table.created": "تاريخ الإنشاء", + "apiKeys.table.lastUsed": "آخر استخدام", + "apiKeys.table.never": "أبدًا", + "apiKeys.table.actions": "الإجراءات", + "apiKeys.table.revoke": "إلغاء", + "apiKeys.table.copyPrefix": "نسخ بادئة المفتاح", + "apiKeys.table.revokeKey": "إلغاء المفتاح", + "apiKeys.revokeDialog.title": "إلغاء مفتاح API", + "apiKeys.revokeDialog.desc": "هل أنت متأكد من إلغاء المفتاح \\\"{name}\\\"؟ لا يمكن التراجع عن هذا الإجراء.", + "apiKeys.revokeDialog.confirm": "نعم، إلغاء", + "apiKeys.revokeDialog.cancel": "إلغاء", + "apiKeys.noKeysGenerated": "لم يتم إنشاء مفاتيح", + "apiKeys.copied": "تم النسخ!" +} diff --git a/frontend/src/lib/i18n/messages/ar/auth.json b/frontend/src/lib/i18n/messages/ar/auth.json new file mode 100644 index 0000000..b300370 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/auth.json @@ -0,0 +1,3 @@ +{ + "auth.brandName": "Wordly" +} diff --git a/frontend/src/lib/i18n/messages/ar/checkout.json b/frontend/src/lib/i18n/messages/ar/checkout.json new file mode 100644 index 0000000..aa51f34 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/checkout.json @@ -0,0 +1,12 @@ +{ + "checkout.activating": "جارٍ التفعيل…", + "checkout.activatingDesc": "نقوم بتحديث اشتراكك، يرجى الانتظار.", + "checkout.paymentConfirmed": "تم تأكيد الدفع!", + "checkout.subscriptionActivated": "تم تفعيل الاشتراك!", + "checkout.planActivated": "تم تفعيل خطة {plan}!", + "checkout.redirectingToProfile": "إعادة التوجيه إلى ملفك الشخصي…", + "checkout.paymentReceived": "تم استلام الدفع", + "checkout.redirecting": "جارٍ إعادة التوجيه…", + "checkout.syncError": "خطأ في المزامنة", + "checkout.networkError": "خطأ في الشبكة. تم تأكيد الدفع — يرجى إعادة تحميل ملفك الشخصي." +} diff --git a/frontend/src/lib/i18n/messages/ar/common.json b/frontend/src/lib/i18n/messages/ar/common.json new file mode 100644 index 0000000..955d293 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/common.json @@ -0,0 +1,4 @@ +{ + "common.loading": "جارٍ التحميل...", + "common.backToHome": "العودة للرئيسية" +} diff --git a/frontend/src/lib/i18n/messages/ar/context.json b/frontend/src/lib/i18n/messages/ar/context.json new file mode 100644 index 0000000..dc5e0b1 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/context.json @@ -0,0 +1,25 @@ +{ + "context.proTitle": "ميزة Pro", + "context.proDesc": "السياق والمصطلحات المهنية متاحة مع خطط Pro وBusiness وEnterprise. توفر ترجمات أكثر دقة من خلال تعليمات ومفردات خاصة بمجالك.", + "context.viewPlans": "عرض الخطط", + "context.title": "السياق والمصطلحات", + "context.subtitle": "حسّن جودة الترجمة من خلال تعليمات ومفردات خاصة بمجالك.", + "context.presets.title": "المصطلحات المهنية", + "context.presets.desc": "تحميل مصطلحات كاملة مع تعليمات ومصطلحات متخصصة", + "context.instructions.title": "تعليمات السياق", + "context.instructions.desc": "تعليمات سيتبعها الذكاء الاصطناعي أثناء الترجمة", + "context.instructions.placeholder": "مثال: أنت تترجم مستندات تقنية HVAC. استخدم مصطلحات الهندسة الدقيقة...", + "context.glossary.title": "المصطلحات التقنية", + "context.glossary.desc": "التنسيق: source=target (واحد في كل سطر). المصطلحات المحملة عبر الإعدادات المسبقة قابلة للتعديل.", + "context.glossary.terms": "مصطلحات في القاموس", + "context.clearAll": "مسح الكل", + "context.saving": "جارٍ الحفظ...", + "context.save": "حفظ", + "context.presets.createGlossary": "إنشاء مسرد", + "context.presets.created": "تم إنشاء المسرد", + "context.presets.createdDesc": "تم إنشاء المسرد \\\"{name}\\\" بـ {count} مصطلحات.", + "context.presets.hint": "انقر على إعداد مسبق لإنشاء مسرد بمصطلحات خاصة بالمجال. أد穹 مصادرك في قسم المسرات.", + "context.glossary.manage": "إدارة المسرات", + "context.saved": "تم الحفظ", + "context.savedDesc": "تم حفظ تعليمات السياق الخاصة بك." +} diff --git a/frontend/src/lib/i18n/messages/ar/cookieConsent.json b/frontend/src/lib/i18n/messages/ar/cookieConsent.json new file mode 100644 index 0000000..a0d40d6 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/cookieConsent.json @@ -0,0 +1,7 @@ +{ + "cookieConsent.title": "ملفات تعريف الارتباط على Wordly", + "cookieConsent.description": "نستخدم ملفات تعريف الارتباط الأساسية لعمل التطبيق (الجلسة، الأمان، اللغة). بإذنك، نستخدم أيضًا ملفات تعريف ارتباط اختيارية لقياس حركة المرور وتحسين المنتج.", + "cookieConsent.acceptAll": "قبول الكل", + "cookieConsent.essentialOnly": "الأساسية فقط", + "cookieConsent.learnMore": "معرفة المزيد" +} diff --git a/frontend/src/lib/i18n/messages/ar/dashboard.json b/frontend/src/lib/i18n/messages/ar/dashboard.json new file mode 100644 index 0000000..9b90201 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/dashboard.json @@ -0,0 +1,111 @@ +{ + "dashboard.nav.translate": "ترجمة", + "dashboard.nav.profile": "ملفي الشخصي", + "dashboard.nav.settings": "الإعدادات", + "dashboard.nav.context": "السياق", + "dashboard.nav.services": "الخدمات", + "dashboard.nav.apiKeys": "مفاتيح API", + "dashboard.nav.glossaries": "المعاجم", + "dashboard.header.title": "لوحة التحكم", + "dashboard.header.subtitle": "إدارة ترجماتك", + "dashboard.header.toggleMenu": "القائمة", + "dashboard.header.profileTitle": "ملفي الشخصي", + "dashboard.sidebar.theme": "المظهر", + "dashboard.sidebar.signOut": "تسجيل الخروج", + "dashboard.sidebar.backHome": "العودة إلى الصفحة الرئيسية", + "dashboard.sidebar.upgradeToPro": "الترقية إلى Pro ←", + "dashboard.translate.pageTitle": "ترجمة مستند", + "dashboard.translate.pageSubtitle": "استورد ملفًا واختر اللغة الهدف", + "dashboard.translate.errorNotificationTitle": "خطأ", + "dashboard.translate.dropzone.uploadAria": "منطقة إسقاط الملفات", + "dashboard.translate.dropzone.title": "اسحب ملفك وأفلته هنا", + "dashboard.translate.dropzone.subtitle": "أو انقر للاختيار (DOCX, XLSX, PPTX, PDF)", + "dashboard.translate.dropzone.replaceFile": "استبدال الملف", + "dashboard.translate.language.source": "لغة المصدر", + "dashboard.translate.language.target": "اللغة الهدف", + "dashboard.translate.language.loading": "جارٍ تحميل اللغات…", + "dashboard.translate.language.autoDetect": "كشف تلقائي", + "dashboard.translate.language.selectPlaceholder": "اختيار…", + "dashboard.translate.language.loadErrorPrefix": "فشل تحميل اللغات", + "dashboard.translate.provider.loading": "جارٍ تحميل مزوّدي الخدمة…", + "dashboard.translate.provider.noneConfigured": "لا يوجد مزوّدو خدمة مُعدّون", + "dashboard.translate.provider.modelTitle": "النموذج", + "dashboard.translate.provider.sectionTitle": "مزوّد الخدمة", + "dashboard.translate.provider.llmDivider": "ذكاء اصطناعي · مدرك للسياق", + "dashboard.translate.provider.llmDividerPro": "ذكاء اصطناعي · مدرك للسياق (Pro)", + "dashboard.translate.provider.upgrade": "الترقية إلى Pro", + "dashboard.translate.provider.upgradeSuffix": "لفتح ترجمة الذكاء الاصطناعي", + "dashboard.translate.trust.zeroRetention": "صفر احتفاظ بالبيانات", + "dashboard.translate.trust.deletedAfter": "تُحذف الملفات بعد المعالجة", + "dashboard.translate.actions.uploading": "جارٍ الرفع…", + "dashboard.translate.actions.translate": "ترجمة", + "dashboard.translate.actions.filePrefix": "الملف: ", + "dashboard.translate.actions.cancel": "إلغاء", + "dashboard.translate.actions.tryAgain": "إعادة المحاولة", + "dashboard.translate.steps.uploading": "جارٍ رفع الملف…", + "dashboard.translate.steps.starting": "جارٍ بدء الترجمة…", + "dashboard.translate.complete.title": "تمت الترجمة بنجاح!", + "dashboard.translate.complete.descNamed": "تمت ترجمة ملفك {name} بنجاح.", + "dashboard.translate.complete.descGeneric": "تمت ترجمة ملفك بنجاح.", + "dashboard.translate.complete.downloading": "جارٍ التنزيل…", + "dashboard.translate.complete.download": "تنزيل", + "dashboard.translate.complete.newTranslation": "ترجمة جديدة", + "dashboard.translate.complete.toastOkTitle": "تم بنجاح", + "dashboard.translate.complete.toastOkDesc": "تم تنزيل {name} بنجاح.", + "dashboard.translate.complete.toastFailTitle": "فشل", + "dashboard.translate.complete.toastFailDesc": "فشلت الترجمة. يرجى إعادة المحاولة.", + "dashboard.translate.sourceDocument": "المستند المصدر", + "dashboard.translate.configuration": "الإعدادات", + "dashboard.translate.translating": "جارٍ الترجمة", + "dashboard.translate.liveMonitor": "المراقبة المباشرة", + "dashboard.translate.summary": "الملخص", + "dashboard.translate.engine": "المحرك", + "dashboard.translate.confidence": "الثقة", + "dashboard.translate.cancel": "إلغاء", + "dashboard.translate.segments": "الأجزاء", + "dashboard.translate.characters": "الأحرف", + "dashboard.translate.elapsed": "المنقضي", + "dashboard.translate.segPerMin": "جزء/دقيقة", + "dashboard.translate.highQuality": "جودة عالية", + "dashboard.translate.quality": "الجودة", + "dashboard.translate.completed": "اكتملت الترجمة", + "dashboard.translate.replace": "استبدال", + "dashboard.translate.pdfMode.title": "وضع ترجمة PDF", + "dashboard.translate.pdfMode.preserveLayout": "الحفاظ على التخطيط", + "dashboard.translate.pdfMode.textOnly": "نص فقط", + "dashboard.translate.pdfMode.preserveLayoutDesc": "يحافظ على الصور والجداول والتنسيق. مثالي لملفات PDF البسيطة.", + "dashboard.translate.pdfMode.textOnlyDesc": "يترجم كل النص بشكل مثالي. مخرجات نظيفة دون مشاكل تخطيط.", + "dashboard.translate.pipeline.upload": "رفع", + "dashboard.translate.pipeline.analyze": "تحليل", + "dashboard.translate.pipeline.translate": "ترجمة", + "dashboard.translate.pipeline.rebuild": "إعادة بناء", + "dashboard.translate.pipeline.finalize": "إنهاء", + "dashboard.translate.progress.processingFallback": "جارٍ المعالجة…", + "dashboard.translate.progress.connectionLost": "فُقد الاتصال. إعادة المحاولة…", + "dashboard.translate.progress.failedTitle": "فشلت الترجمة", + "dashboard.translate.error.unexpected": "حدث خطأ غير متوقع. يرجى المحاولة مرة أخرى.", + "dashboard.translate.error.noResult": "لم تُنتج الترجمة أي نتائج. تحقق من أن المستند يحتوي على نص، ثم أعد المحاولة أو اختر محركًا آخر.", + "dashboard.translate.error.apiKey": "مفتاح API غير صالح أو مفقود. اتصل بالمسؤول لإعداد مفاتيح API.", + "dashboard.translate.error.quota": "تم بلوغ حد الاستخدام. أعد المحاولة بعد بضع دقائق أو اختر محركًا آخر.", + "dashboard.translate.error.timeout": "انتهت مهلة الاتصال بخدمة الترجمة. تحقق من شبكتك وأعد المحاولة.", + "dashboard.translate.error.sessionExpired": "انتهت الجلسة. انقر على إعادة المحاولة لإعادة تشغيل الترجمة.", + "dashboard.translate.error.empty": "يبدو أن المستند فارغ أو لا يحتوي على نص قابل للترجمة (صورة PDF ممسوحة ضوئيًا؟).", + "dashboard.translate.error.unsupported": "تنسيق ملف غير مدعوم أو ملف تالف.", + "dashboard.translate.error.connection": "فُقد الاتصال. تحقق من شبكتك وأعد المحاولة.", + "dashboard.translate.error.generic": "فشلت الترجمة: {detail}", + "dashboard.translate.error.title": "فشلت الترجمة", + "dashboard.translate.retry": "إعادة محاولة الترجمة", + "dashboard.translate.newFile": "ملف جديد", + "dashboard.translate.modeAI": "وضع الذكاء الاصطناعي", + "dashboard.translate.modeClassic": "الوضع الكلاسيكي", + "dashboard.translate.glossaryLLMHint": "القواميس المصطلحية متاحة في وضع الذكاء الاصطناعي", + "dashboard.translate.submitting": "جارٍ الإرسال...", + "dashboard.translate.submit": "بدء الترجمة", + "dashboard.translate.noFile": "قم بتحميل ملف أولاً", + "dashboard.translate.noTargetLang": "اختر لغة الهدف", + "dashboard.topbar.interfaceLabel": "واجهة الترجمة", + "dashboard.topbar.premiumAccess": "وصول مميز", + "dashboard.checkoutSyncError": "خطأ في مزامنة الدفع.", + "dashboard.networkRefresh": "خطأ في الشبكة. يرجى تحديث الصفحة.", + "dashboard.continueToTranslate": "متابعة إلى الترجمة" +} diff --git a/frontend/src/lib/i18n/messages/ar/fileUploader.json b/frontend/src/lib/i18n/messages/ar/fileUploader.json new file mode 100644 index 0000000..ef287e1 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/fileUploader.json @@ -0,0 +1,31 @@ +{ + "fileUploader.uploadDocument": "تحميل المستند", + "fileUploader.uploadDesc": "اسحب وأفلت أو انقر لتحديد ملف (Excel, Word, PowerPoint)", + "fileUploader.dropHere": "أفلت ملفك هنا…", + "fileUploader.dragAndDrop": "اسحب وأفلت المستند هنا", + "fileUploader.orClickBrowse": "أو انقر للتصفح", + "fileUploader.preview": "معاينة", + "fileUploader.translationOptions": "خيارات الترجمة", + "fileUploader.configureSettings": "اضبط إعدادات الترجمة", + "fileUploader.targetLanguage": "اللغة المستهدفة", + "fileUploader.selectLanguage": "اختر اللغة", + "fileUploader.translationProvider": "مزود الترجمة", + "fileUploader.selectProvider": "اختر المزود", + "fileUploader.advancedOptions": "خيارات متقدمة", + "fileUploader.translateImages": "ترجمة الصور", + "fileUploader.translating": "جارٍ الترجمة…", + "fileUploader.translateDocument": "ترجمة المستند", + "fileUploader.processing": "جارٍ المعالجة…", + "fileUploader.translationError": "خطأ في الترجمة", + "fileUploader.translationComplete": "اكتملت الترجمة!", + "fileUploader.translationCompleteDesc": "تمت ترجمة مستندك بنجاح مع الحفاظ على جميع التنسيقات.", + "fileUploader.download": "تنزيل المستند المترجم", + "fileUploader.webgpuUnsupported": "WebGPU غير مدعوم في هذا المتصفح. يرجى استخدام Chrome 113+ أو Edge 113+.", + "fileUploader.webllmNotLoaded": "نموذج WebLLM غير محمّل. اذهب إلى الإعدادات > خدمات الترجمة لتحميل نموذج أولاً.", + "fileUploader.extracting": "استخراج النصوص من المستند…", + "fileUploader.noTranslatable": "لم يتم العثور على نص قابل للترجمة في المستند", + "fileUploader.foundTexts": "تم العثور على {count} نصوص للترجمة", + "fileUploader.translatingItem": "ترجمة {current}/{total}: \\\"{preview}\\\"", + "fileUploader.reconstructing": "إعادة بناء المستند…", + "fileUploader.translatingLocally": "ترجمة محلية باستخدام WebLLM…" +} diff --git a/frontend/src/lib/i18n/messages/ar/glossaries.json b/frontend/src/lib/i18n/messages/ar/glossaries.json new file mode 100644 index 0000000..e3b4fae --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/glossaries.json @@ -0,0 +1,189 @@ +{ + "glossaries.yourGlossaries": "معاجمك", + "glossaries.title": "المعاجم والسياق", + "glossaries.description": "قم بإدارة معاجمك وتعليمات السياق للحصول على ترجمات أكثر دقة.", + "glossaries.createNew": "إنشاء جديد", + "glossaries.empty": "لا توجد معاجم بعد", + "glossaries.emptyDesc": "أنشئ أول معجم لك أو حمّل إعدادًا مسبقًا احترافيًا أعلاه", + "glossaries.defineTerms": "مصطلحات", + "glossaries.aboutTitle": "حول المعاجم", + "glossaries.aboutDesc": "تتيح لك المعاجم تحديد ترجمات دقيقة لمصطلحات معينة. عند الترجمة، يتم استخدام مصطلحات المعجم لضمان ترجمات متسقة ودقيقة.", + "glossaries.aboutFormat": "كل مصطلح له كلمة مصدر وترجمات بلغات متعددة. حدد معجمًا في صفحة الترجمة لتطبيقه.", + "glossaries.toast.created": "تم إنشاء المعجم", + "glossaries.toast.createdDesc": "تم إنشاء المعجم \\\"{name}\\\".", + "glossaries.toast.imported": "تم استيراد المعجم", + "glossaries.toast.importedDesc": "تم استيراد المعجم \\\"{name}\\\".", + "glossaries.toast.updated": "تم تحديث المعجم", + "glossaries.toast.updatedDesc": "تم تحديث المعجم \\\"{name}\\\".", + "glossaries.toast.deleted": "تم حذف المعجم", + "glossaries.toast.deletedDesc": "تم حذف المعجم.", + "glossaries.toast.error": "خطأ", + "glossaries.toast.errorCreate": "فشل إنشاء المعجم", + "glossaries.toast.errorImport": "فشل استيراد المعجم", + "glossaries.toast.errorUpdate": "فشل تحديث المعجم", + "glossaries.toast.errorDelete": "فشل حذف المعجم", + "glossaries.dialog.title": "معجم جديد", + "glossaries.dialog.description": "أنشئ معجمًا لترجماتك", + "glossaries.dialog.nameLabel": "الاسم", + "glossaries.dialog.namePlaceholder": "معجمي", + "glossaries.dialog.tabTemplates": "القوالب", + "glossaries.dialog.tabFile": "ملف", + "glossaries.dialog.tabManual": "يدوي", + "glossaries.dialog.cancel": "إلغاء", + "glossaries.dialog.creating": "جارٍ الإنشاء…", + "glossaries.dialog.importing": "جارٍ الاستيراد…", + "glossaries.dialog.importBtn": "استيراد", + "glossaries.dialog.selectPrompt": "اختيار", + "glossaries.dialog.createBtn": "إنشاء", + "glossaries.dialog.createEmpty": "إنشاء فارغ", + "glossaries.dialog.terms": "مصطلحات", + "glossaries.dialog.templatesDesc": "اختر قالبًا مُعدًّا مسبقًا", + "glossaries.dialog.templatesEmpty": "لا توجد قوالب متاحة", + "glossaries.dialog.dropTitle": "اسحب ملف CSV هنا", + "glossaries.dialog.dropOr": "أو", + "glossaries.dialog.dropFormats": "CSV, TSV, TXT", + "glossaries.termEditor.addTerm": "إضافة مصطلح", + "glossaries.termEditor.maxReached": "تم بلوغ الحد الأقصى {max} من المصطلحات لكل قاموس.", + "glossaries.dialog.formatTitle": "التنسيق", + "glossaries.dialog.formatDesc": "المصدر،الهدف (واحدة لكل سطر)", + "glossaries.dialog.formatNote": "يُتجاهل السطر الأول عند اكتشاف ترويسة", + "glossaries.dialog.errorFormat": "تنسيق غير مدعوم", + "glossaries.dialog.errorSize": "الملف كبير جدًا", + "glossaries.dialog.errorEmpty": "ملف فارغ", + "glossaries.dialog.errorRead": "خطأ في القراءة", + "glossaries.dialog.parsing": "جارٍ التحليل…", + "glossaries.dialog.termsImported": "مصطلحات مستوردة", + "glossaries.dialog.changeFile": "تغيير الملف", + "glossaries.dialog.retry": "إعادة المحاولة", + "glossaries.edit.title": "Modifier le glossaire", + "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", + "glossaries.edit.nameLabel": "Nom du glossaire", + "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", + "glossaries.edit.sourceLang": "Langue source", + "glossaries.edit.targetLang": "Langue cible", + "glossaries.edit.termsLabel": "Termes ({count} valides)", + "glossaries.edit.exportCsv": "Exporter CSV", + "glossaries.edit.importCsv": "Importer CSV", + "glossaries.edit.cancel": "Annuler", + "glossaries.edit.saving": "Enregistrement...", + "glossaries.edit.saveChanges": "Enregistrer les modifications", + "glossaries.edit.importFailedTitle": "Échec de l'importation", + "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", + "glossaries.edit.importSuccessTitle": "Importation réussie", + "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", + "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", + "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", + "glossaries.delete.title": "Supprimer le glossaire", + "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", + "glossaries.delete.warning": "Cette action est irréversible", + "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", + "glossaries.delete.cancel": "Annuler", + "glossaries.delete.deleting": "Suppression...", + "glossaries.delete.deleteBtn": "Supprimer", + "glossaries.upgrade.title": "Glossaires", + "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", + "glossaries.upgrade.feature1": "Créez plusieurs glossaires", + "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", + "glossaries.upgrade.feature3": "Importez/exportez via CSV", + "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", + "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", + "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", + "glossaries.upgrade.proLabel": "Pro", + "glossaries.upgrade.upgradeBtn": "Passer à Pro", + "glossaries.loading": "Chargement...", + "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", + "glossaries.howItWorks.step1Title": "Configurez ici", + "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", + "glossaries.howItWorks.step2Title": "Activez dans Traduire", + "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", + "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", + "glossaries.howItWorks.goToTranslate": "Aller à Traduire", + "glossaries.status.unsaved": "Non enregistré", + "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", + "glossaries.status.inactive": "Inactif", + "glossaries.instructions.whatForBold": "À quoi ça sert ?", + "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", + "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", + "glossaries.instructions.charCount": "{count} caractères", + "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", + "glossaries.instructions.clearAll": "Tout effacer", + "glossaries.instructions.saving": "Enregistrement…", + "glossaries.instructions.saved": "Enregistré", + "glossaries.presets.whatForBold": "À quoi ça sert ?", + "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", + "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", + "glossaries.presets.creating": "Création…", + "glossaries.presets.alreadyImported": "Déjà importé", + "glossaries.presets.it.title": "IT / Logiciel", + "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", + "glossaries.presets.legal.title": "Juridique / Contrats", + "glossaries.presets.legal.desc": "Droit des affaires, contentieux", + "glossaries.presets.medical.title": "Médical / Santé", + "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", + "glossaries.presets.finance.title": "Finance / Comptabilité", + "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", + "glossaries.presets.marketing.title": "Marketing / Publicité", + "glossaries.presets.marketing.desc": "Digital, branding, analytics", + "glossaries.presets.hr.title": "RH / Ressources Humaines", + "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", + "glossaries.presets.scientific.title": "Scientifique / Recherche", + "glossaries.presets.scientific.desc": "Publications, thèses, articles", + "glossaries.presets.ecommerce.title": "E-commerce / Vente", + "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", + "glossaries.grid.title": "Vos", + "glossaries.grid.titleHighlight": "glossaires", + "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", + "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", + "glossaries.grid.activeTranslation": "Traduction active :", + "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", + "glossaries.badge.compatible": "Compatible", + "glossaries.badge.otherTarget": "Autre cible", + "glossaries.card.editTerms": "Modifier les termes", + "glossaries.card.created": "تم الإنشاء", + "glossaries.card.term": "مصطلح", + "glossaries.card.delete": "Supprimer", + "glossaries.grid.searchPlaceholder": "Search a glossary…", + "glossaries.grid.noResults": "No results for this search.", + "glossaries.detail.backToList": "Back to glossaries", + "glossaries.detail.save": "Save", + "glossaries.detail.savedTitle": "Saved", + "glossaries.detail.savedDesc": "The glossary has been updated.", + "glossaries.detail.settingsTitle": "Settings", + "glossaries.detail.sourceLang": "Source language", + "glossaries.detail.targetLang": "Target language", + "glossaries.detail.termsTitle": "Terms", + "glossaries.detail.terms": "terms", + "glossaries.detail.searchTerms": "Filter…", + "glossaries.detail.noTerms": "No terms yet.", + "glossaries.detail.addFirstTerm": "Add the first term", + "glossaries.detail.addTerm": "Add a term", + "glossaries.detail.maxReached": "Maximum limit reached", + "glossaries.detail.source": "Source", + "glossaries.detail.target": "Target", + "glossaries.detail.sourcePlaceholder": "source term", + "glossaries.detail.targetPlaceholder": "target term", + "glossaries.detail.csvTitle": "CSV", + "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", + "glossaries.detail.export": "Export", + "glossaries.detail.import": "Import", + "glossaries.detail.dangerTitle": "Danger zone", + "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", + "glossaries.detail.deleteGlossary": "Delete this glossary", + "glossaries.detail.confirmDelete": "Confirm deletion?", + "glossaries.detail.confirm": "Confirm", + "glossaries.detail.cancel": "Cancel", + "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", + "glossaries.detail.sourceLocked": "fixed", + "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", + "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", + "glossaries.detail.notFoundTitle": "Glossary not found", + "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", + "glossaries.detail.maxTermsTitle": "Limit reached", + "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", + "glossaries.detail.importEmptyTitle": "Empty file", + "glossaries.detail.importEmptyDesc": "No terms detected in this file.", + "glossaries.detail.importedTitle": "Imported", + "glossaries.detail.importedDesc": "{count} terms imported.", + "glossaries.detail.importErrorTitle": "Read error", + "glossaries.detail.importErrorDesc": "Unable to read the file." +} diff --git a/frontend/src/lib/i18n/messages/ar/index.ts b/frontend/src/lib/i18n/messages/ar/index.ts new file mode 100644 index 0000000..4e078e9 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/index.ts @@ -0,0 +1,56 @@ +// Auto-generated by scripts/generate_i18n_index.py +// Merges all namespace JSON files for locale "ar". + +import admin from "./admin.json"; +import apiKeys from "./apiKeys.json"; +import auth from "./auth.json"; +import checkout from "./checkout.json"; +import common from "./common.json"; +import context from "./context.json"; +import cookieConsent from "./cookieConsent.json"; +import dashboard from "./dashboard.json"; +import fileUploader from "./fileUploader.json"; +import glossaries from "./glossaries.json"; +import landing from "./landing.json"; +import langSelector from "./langSelector.json"; +import layout from "./layout.json"; +import login from "./login.json"; +import memento from "./memento.json"; +import pricing from "./pricing.json"; +import profile from "./profile.json"; +import providerSelector from "./providerSelector.json"; +import providerTheme from "./providerTheme.json"; +import register from "./register.json"; +import services from "./services.json"; +import settings from "./settings.json"; +import translate from "./translate.json"; +import translateComplete from "./translateComplete.json"; + +const messages: Record = { + ...admin, + ...apiKeys, + ...auth, + ...checkout, + ...common, + ...context, + ...cookieConsent, + ...dashboard, + ...fileUploader, + ...glossaries, + ...landing, + ...langSelector, + ...layout, + ...login, + ...memento, + ...pricing, + ...profile, + ...providerSelector, + ...providerTheme, + ...register, + ...services, + ...settings, + ...translate, + ...translateComplete, +}; + +export default messages; diff --git a/frontend/src/lib/i18n/messages/ar/landing.json b/frontend/src/lib/i18n/messages/ar/landing.json new file mode 100644 index 0000000..2618335 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/landing.json @@ -0,0 +1,146 @@ +{ + "landing.nav.why": "لماذا نحن؟", + "landing.nav.formats": "التنسيقات", + "landing.nav.pricing": "الأسعار", + "landing.nav.login": "تسجيل الدخول", + "landing.nav.startFree": "ابدأ مجانًا", + "landing.hero.tag": "ذكاء اصطناعي احترافي للمستندات", + "landing.hero.titleLine1": "ترجم مستنداتك.", + "landing.hero.titleLine2": "مع تنسيق مثالي.", + "landing.hero.description": "المترجم الوحيد الذي يحافظ على SmartArt والرسوم البيانية وجداول المحتويات والأشكال والتخطيطات المعقدة — تمامًا كما كانت.", + "landing.hero.ctaMain": "ابدأ مجانًا — مستندان/شهر", + "landing.hero.ctaSec": "عرض العروض", + "landing.hero.deleted": "الملفات تُحذف بعد 60 دقيقة", + "landing.hero.noHidden": "بدون رسوم خفية", + "landing.hero.preview": "معاينة قبل الدفع", + "landing.hero.formattedOk": "التنسيق سليم", + "landing.hero.aiActive": "ترجمة الذكاء الاصطناعي نشطة", + "landing.steps.title": "كيف يعمل؟", + "landing.steps.subtitle": "ثلاث خطوات. صفر فقدان في التنسيق.", + "landing.steps.step1.num": "01", + "landing.steps.step1.title": "ارفع ملفك", + "landing.steps.step1.desc": "اسحب وأفلت مستند Excel أو Word أو PowerPoint أو PDF.", + "landing.steps.step2.num": "02", + "landing.steps.step2.title": "اختر اللغة والمحرك", + "landing.steps.step2.desc": "حدد اللغة المستهدفة والمحرك — كلاسيكي أو ذكاء اصطناعي سياقي.", + "landing.steps.step3.num": "03", + "landing.steps.step3.title": "حمّل النتيجة", + "landing.steps.step3.desc": "احصل على مستندك المترجم بتنسيق مطابق تمامًا للأصل.", + "landing.features.tag": "محرك ترجمة بالذكاء الاصطناعي", + "landing.features.title": "ترجمة تفهم مجالك", + "landing.features.description": "نماذج الذكاء الاصطناعي لدينا تحلل السياق وتحترم مصطلحاتك وحتى تترجم النصوص داخل الصور.", + "landing.features.context.title": "سياق الصناعة", + "landing.features.context.desc": "صِف مجالك واحصل على ترجمات مخصصة، وليس عامة.", + "landing.features.glossary.title": "قواميس المصطلحات", + "landing.features.glossary.desc": "حدد مصطلحاتك التقنية. CTA تبقى «وحدة معالجة الهواء»، وليس «الدعوة للإجراء».", + "landing.features.vision.title": "التعرف على الصور", + "landing.features.vision.desc": "النص المضمن في الصور والمخططات والرسوم البياني يتم اكتشافه وترجمته.", + "landing.features.demo.source": "المصدر (FR)", + "landing.features.demo.google": "Google Translate", + "landing.features.demo.ours": "ذكاؤنا الاصطناعي", + "landing.layout.title": "تنسيقك،", + "landing.layout.title2": "محفوظ بشكل مثالي", + "landing.layout.subtitle": "المترجمون الآخرون يدمرون تخطيطك. نحن لا.", + "landing.layout.p1.title": "SmartArt والمخططات", + "landing.layout.p1.desc": "الهياكل التنظيمية، المخططات الانسيابية، التسلسلات الهرمية — كلها مترجمة بشكل مطابق.", + "landing.layout.p2.title": "جداول المحتويات", + "landing.layout.p2.desc": "إدخالات جدول المحتويات وأرقام الصفحات والمراجع المتبادلة محدثة بشكل صحيح.", + "landing.layout.p3.title": "الرسوم والمخططات البيانية", + "landing.layout.p3.desc": "العناوين، تسميات المحاور، التسميات التوضيحية وأسماء السلاسل — كل شيء مترجم.", + "landing.layout.p4.title": "الأشكال ومربعات النص", + "landing.layout.p4.desc": "مستطيلات، كتل مستديرة، تعليقات توضيحية — محلية في كل مكان.", + "landing.layout.p5.title": "الرؤوس والتذييلات", + "landing.layout.p5.desc": "الرؤوس والتذييلات والحواشي لا تُفوت أبدًا.", + "landing.layout.p6.title": "130+ لغة", + "landing.layout.p6.desc": "Google Translate و DeepL ومحركات ذكاء اصطناعي احترافية.", + "landing.formats.title": "كل تنسيق،", + "landing.formats.title2": "كل عنصر", + "landing.formats.subtitle": "نترجم ما يفوته الآخرون. عملك يستحق توثيقًا لا تشوبه شائبة.", + "landing.formats.word.name": "Word", + "landing.formats.word.i1": "الفقرات والعناوين", + "landing.formats.word.i2": "الجداول والرسوم البيانية", + "landing.formats.word.i3": "مخططات SmartArt", + "landing.formats.word.i4": "جدول المحتويات", + "landing.formats.word.i5": "الرؤوس والتذييلات", + "landing.formats.word.i6": "الأشكال ومربعات النص", + "landing.formats.word.i7": "الحواشي والتعليقات الختامية", + "landing.formats.excel.name": "Excel", + "landing.formats.excel.i1": "قيم الخلايا", + "landing.formats.excel.i2": "أسماء الأوراق", + "landing.formats.excel.i3": "الرسوم والتسميات", + "landing.formats.excel.i4": "الرؤوس والتذييلات", + "landing.formats.excel.i5": "الخلايا المدمجة محفوظة", + "landing.formats.pptx.name": "PowerPoint", + "landing.formats.pptx.i1": "نص الشرائح والملاحظات", + "landing.formats.pptx.i2": "الرسوم والمخططات", + "landing.formats.pptx.i3": "الأشكال ومربعات النص", + "landing.formats.pptx.i4": "التخطيطات الرئيسية", + "landing.formats.pptx.i5": "الرسوم المتحركة محفوظة", + "landing.formats.pdf.name": "PDF", + "landing.formats.pdf.i1": "ملفات PDF النصية", + "landing.formats.pdf.i2": "التخطيط محفوظ", + "landing.formats.pdf.i3": "الصور في مكانها", + "landing.formats.pdf.i4": "الجداول محفوظة", + "landing.formats.pdf.i5": "الإخراج كـ DOCX أو PDF", + "landing.pricing.title": "أسعار بسيطة وشفافة", + "landing.pricing.subtitle": "ما تراه هو ما تدفعه. بدون رسوم خفية.", + "landing.pricing.monthly": "شهريًا", + "landing.pricing.annual": "سنويًا", + "landing.pricing.bestValue": "الأكثر شعبية", + "landing.pricing.month": "/شهر", + "landing.pricing.footer": "السعر المعروض هو السعر الذي تدفعه. بدون رسوم خفية بعد الترجمة.", + "landing.pricing.starter.name": "Starter", + "landing.pricing.starter.desc": "للأفراد والمشاريع الصغيرة", + "landing.pricing.starter.f1": "50 مستند / شهر", + "landing.pricing.starter.f2": "حتى 50 صفحة لكل مستند", + "landing.pricing.starter.f3": "Google Translate + DeepL", + "landing.pricing.starter.f4": "ملفات حتى 10 ميجابايت", + "landing.pricing.starter.cta": "ابدأ الآن", + "landing.pricing.pro.name": "Pro", + "landing.pricing.pro.desc": "للمحترفين المتميزين", + "landing.pricing.pro.f1": "200 مستند / شهر", + "landing.pricing.pro.f2": "حتى 200 صفحة لكل مستند", + "landing.pricing.pro.f3": "ترجمة بالذكاء الاصطناعي", + "landing.pricing.pro.f4": "Google + DeepL مشمولان", + "landing.pricing.pro.f5": "قواميس وأوامر مخصصة", + "landing.pricing.pro.f6": "دعم ذو أولوية", + "landing.pricing.pro.cta": "جرّب Pro", + "landing.pricing.business.name": "الأعمال", + "landing.pricing.business.desc": "للفرق ذات الاحتياجات الكبيرة", + "landing.pricing.business.f1": "1,000 مستند / شهر", + "landing.pricing.business.f2": "حتى 500 صفحة لكل مستند", + "landing.pricing.business.f3": "ذكاء اصطناعي متميز (Claude)", + "landing.pricing.business.f4": "جميع المزودين + واجهة برمجة التطبيقات", + "landing.pricing.business.f5": "خطاطف الويب والأتمتة", + "landing.pricing.business.f6": "5 مقاعد للفريق", + "landing.pricing.business.cta": "تواصل معنا", + "landing.cta.title": "ابدأ الترجمة في 30 ثانية", + "landing.cta.subtitle": "لا حاجة لبطاقة ائتمان. جرّب مجانًا الآن وأعد الحياة إلى مستنداتك متعددة اللغات.", + "landing.cta.button": "إنشاء حساب مجاني", + "landing.cta.secure": "محمي بتشفير AES-256", + "landing.footer.desc": "خبراء في الترجمة الذكية للمستندات. نمزج بين فن التنسيق وعلم الذكاء الاصطناعي السياقي.", + "landing.footer.product": "المنتج", + "landing.footer.resources": "الموارد", + "landing.footer.legal": "قانوني", + "landing.footer.rights": "© 2026 Wordly.art — جميع الحقوق محفوظة.", + "landing.hero.contextEngine": "ترجمة مكتشفة: مصطلح صيانة تقني لأنظمة التدفئة والتهوية...", + "landing.hero.liveAnalysis": "تحليل مباشر", + "landing.hero.termsDetected": "مصطلحات مكتشفة", + "landing.steps.process": "العملية", + "landing.translate.newProject": "مشروع جديد", + "landing.translate.title": "ترجمة مستند", + "landing.translate.subtitle": "استورد ملفًا واختر اللغة المستهدفة", + "landing.translate.sourceDocument": "المستند المصدر", + "landing.translate.configuration": "الإعدادات", + "landing.translate.sourceLang": "لغة المصدر", + "landing.translate.targetLang": "اللغة المستهدفة", + "landing.translate.provider": "المزود", + "landing.translate.startTranslation": "بدء الترجمة", + "landing.translate.zeroRetention": "صفر احتفاظ", + "landing.translate.filesDeleted": "الملفات محذوفة بعد المعالجة", + "landing.translate.dropHere": "اسحب وأفلت هنا", + "landing.translate.supportedFormats": "ملفات DOCX, XLSX, PPTX أو PDF مدعومة", + "landing.translate.aiAnalysis": "تحليل AI نشط", + "landing.translate.processing": "جاري المعالجة", + "landing.translate.preservingLayout": "جاري الحفاظ على التنسيق" +} diff --git a/frontend/src/lib/i18n/messages/ar/langSelector.json b/frontend/src/lib/i18n/messages/ar/langSelector.json new file mode 100644 index 0000000..f2ec85b --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/langSelector.json @@ -0,0 +1,7 @@ +{ + "langSelector.search": "بحث…", + "langSelector.noResults": "لا توجد نتائج", + "langSelector.source": "المصدر", + "langSelector.target": "الهدف", + "langSelector.swap": "تبديل" +} diff --git a/frontend/src/lib/i18n/messages/ar/layout.json b/frontend/src/lib/i18n/messages/ar/layout.json new file mode 100644 index 0000000..785cbbd --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/layout.json @@ -0,0 +1,5 @@ +{ + "layout.nav.apiAccess": "وصول API", + "layout.footer.terms": "الشروط", + "layout.footer.privacy": "الخصوصية" +} diff --git a/frontend/src/lib/i18n/messages/ar/login.json b/frontend/src/lib/i18n/messages/ar/login.json new file mode 100644 index 0000000..2c4026d --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/login.json @@ -0,0 +1,6 @@ +{ + "login.orContinueWith": "أو تابع بالبريد الإلكتروني", + "login.google.connecting": "جارٍ الاتصال…", + "login.google.errorGeneric": "حدث خطأ في تسجيل الدخول عبر Google.", + "login.google.errorFailed": "فشل تسجيل الدخول عبر Google. حاول مرة أخرى." +} diff --git a/frontend/src/lib/i18n/messages/ar/memento.json b/frontend/src/lib/i18n/messages/ar/memento.json new file mode 100644 index 0000000..87d6d32 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/memento.json @@ -0,0 +1,6 @@ +{ + "memento.title": "اكتشف Momento", + "memento.slogan": "Momento ليس مجرد تطبيق ملاحظات. إنه نظام بيئي ذكي يربط ويحلل ويطور أفكارك في الوقت الفعلي باستخدام 6 وكلاء ذكاء اصطناعي وبحث دلالي متقدم.", + "memento.ctaFree": "ابدأ مجاناً", + "memento.ctaMore": "اعرف المزيد" +} diff --git a/frontend/src/lib/i18n/messages/ar/pricing.json b/frontend/src/lib/i18n/messages/ar/pricing.json new file mode 100644 index 0000000..aaddf39 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/pricing.json @@ -0,0 +1,151 @@ +{ + "pricing.nav.back": "رجوع", + "pricing.nav.home": "الرئيسية", + "pricing.nav.mySubscription": "اشتراكي", + "pricing.header.badge": "نماذج الذكاء الاصطناعي المحدّثة — مارس 2026", + "pricing.header.title": "خطة لكل احتياج", + "pricing.header.subtitle": "ترجم مستندات Word و Excel و PowerPoint مع الحفاظ على التنسيق الأصلي. بدون الحاجة إلى مفتاح API.", + "pricing.billing.monthly": "شهري", + "pricing.billing.yearly": "سنوي", + "pricing.plans.free.name": "مجاني", + "pricing.plans.starter.name": "Starter", + "pricing.plans.pro.name": "Pro", + "pricing.plans.business.name": "Business", + "pricing.plans.enterprise.name": "Enterprise", + "pricing.plans.free.description": "مثالي لاكتشاف التطبيق", + "pricing.plans.starter.description": "للأفراد والمشاريع الصغيرة", + "pricing.plans.pro.description": "للمحترفين والفرق النامية", + "pricing.plans.business.description": "للفرق والمؤسسات", + "pricing.plans.enterprise.description": "حلول مخصصة للمؤسسات الكبيرة", + "pricing.plans.pro.highlight": "الأكثر شعبية", + "pricing.plans.pro.badge": "رائج", + "pricing.plans.enterprise.badge": "حسب الطلب", + "pricing.plans.free.feat1": "5 مستندات / شهر", + "pricing.plans.free.feat2": "حتى 15 صفحة لكل مستند", + "pricing.plans.free.feat3": "ترجمة Google مشمولة", + "pricing.plans.free.feat4": "جميع اللغات (130+)", + "pricing.plans.free.feat5": "دعم المجتمع", + "pricing.plans.starter.feat1": "50 مستندًا / شهر", + "pricing.plans.starter.feat2": "حتى 50 صفحة لكل مستند", + "pricing.plans.starter.feat3": "ترجمة Google + DeepL", + "pricing.plans.starter.feat4": "ملفات حتى 10 ميغابايت", + "pricing.plans.starter.feat5": "دعم عبر البريد الإلكتروني", + "pricing.plans.starter.feat6": "سجل 30 يومًا", + "pricing.plans.pro.feat1": "200 مستند / شهر", + "pricing.plans.pro.feat2": "حتى 200 صفحة لكل مستند", + "pricing.plans.pro.feat3": "ترجمة الذكاء الاصطناعي الأساسية", + "pricing.plans.pro.feat4": "ترجمة Google + DeepL", + "pricing.plans.pro.feat5": "ملفات حتى 25 ميغابايت", + "pricing.plans.pro.feat6": "معاجم مخصصة", + "pricing.plans.pro.feat7": "دعم ذو أولوية", + "pricing.plans.pro.feat8": "سجل 90 يومًا", + "pricing.plans.business.feat1": "1 000 مستند / شهر", + "pricing.plans.business.feat2": "حتى 500 صفحة لكل مستند", + "pricing.plans.business.feat3": "AI أساسية + متميزة (Claude Haiku)", + "pricing.plans.business.feat4": "جميع مزوّدي الترجمة", + "pricing.plans.business.feat5": "ملفات حتى 50 ميغابايت", + "pricing.plans.business.feat6": "وصول API (10 000 استدعاء/شهر)", + "pricing.plans.business.feat7": "ويب هوك للإشعارات", + "pricing.plans.business.feat8": "دعم مخصص", + "pricing.plans.business.feat9": "سجل سنة واحدة", + "pricing.plans.business.feat10": "تحليلات متقدمة", + "pricing.plans.enterprise.feat1": "مستندات بلا حدود", + "pricing.plans.enterprise.feat2": "جميع نماذج AI (GPT-5, Claude Opus 4.6…)", + "pricing.plans.enterprise.feat3": "نشر محلي أو سحابة مخصصة", + "pricing.plans.enterprise.feat4": "SLA 99.9% مضمون", + "pricing.plans.enterprise.feat5": "دعم مخصص على مدار الساعة", + "pricing.plans.enterprise.feat6": "العلامة البيضاء (White-label)", + "pricing.plans.enterprise.feat7": "فرق بلا حدود", + "pricing.plans.enterprise.feat8": "تكاملات مخصصة", + "pricing.card.onRequest": "حسب الطلب", + "pricing.card.free": "مجاني", + "pricing.card.perMonth": "/شهر", + "pricing.card.billedYearly": "يُحاسب {price} € / سنة", + "pricing.card.documents": "المستندات", + "pricing.card.pagesMax": "الحد الأقصى للصفحات", + "pricing.card.aiTranslation": "ترجمة AI", + "pricing.card.unlimited": "بلا حدود", + "pricing.card.perMonthStat": "/ شهر", + "pricing.card.perDoc": "ص / مستند", + "pricing.card.aiEssential": "أساسي", + "pricing.card.aiEssentialPremium": "أساسي + متميز", + "pricing.card.aiCustom": "مخصص", + "pricing.card.myPlan": "خطتي", + "pricing.card.managePlan": "إدارة خطتي", + "pricing.card.startFree": "ابدأ مجانًا", + "pricing.card.contactUs": "تواصل معنا", + "pricing.card.choosePlan": "اختر هذه الخطة", + "pricing.card.processing": "جارٍ المعالجة…", + "pricing.comparison.title": "مقارنة تفصيلية", + "pricing.comparison.subtitle": "كل ما هو مشمول في كل خطة", + "pricing.comparison.feature": "الميزة", + "pricing.comparison.docsPerMonth": "المستندات / شهر", + "pricing.comparison.pagesMaxPerDoc": "الحد الأقصى للصفحات / مستند", + "pricing.comparison.maxFileSize": "الحد الأقصى لحجم الملف", + "pricing.comparison.googleTranslation": "ترجمة Google", + "pricing.comparison.deepl": "DeepL", + "pricing.comparison.aiEssential": "ترجمة AI أساسية", + "pricing.comparison.aiPremium": "ترجمة AI متميزة", + "pricing.comparison.apiAccess": "وصول API", + "pricing.comparison.priorityProcessing": "معالجة ذات أولوية", + "pricing.comparison.support": "الدعم", + "pricing.comparison.support.community": "المجتمع", + "pricing.comparison.support.email": "البريد الإلكتروني", + "pricing.comparison.support.priority": "ذو أولوية", + "pricing.comparison.support.dedicated": "مخصص", + "pricing.comparison.mb": "ميغابايت", + "pricing.credits.title": "أرصدة إضافية", + "pricing.credits.subtitle": "تحتاج المزيد؟ اشترِ أرصدة فردية بدون اشتراك.", + "pricing.credits.perPage": "رصيد واحد = صفحة واحدة مترجمة.", + "pricing.credits.bestValue": "أفضل قيمة", + "pricing.credits.unit": "أرصدة", + "pricing.credits.centsPerCredit": "سنت / رصيد", + "pricing.credits.buy": "شراء", + "pricing.trust.encryption.title": "تشفير شامل", + "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 في حالة السكون", + "pricing.trust.languages.title": "+130 لغة", + "pricing.trust.languages.sub": "بما فيها العربية والفارسية والعبرية (RTL)", + "pricing.trust.parallel.title": "معالجة متوازية", + "pricing.trust.parallel.sub": "ذكاء اصطناعي متعدد المسارات فائق السرعة", + "pricing.trust.availability.title": "متاح على مدار الساعة", + "pricing.trust.availability.sub": "ضمان وقت تشغيل 99.9%", + "pricing.aiModels.title": "نماذج الذكاء الاصطناعي — مارس 2026", + "pricing.aiModels.essential.title": "ترجمة AI أساسية", + "pricing.aiModels.essential.plan": "خطة Pro", + "pricing.aiModels.essential.descPrefix": "مبني على", + "pricing.aiModels.essential.descSuffix": "— أنموذج الذكاء الاصطناعي الأكثر فعالية من حيث التكلفة لعام 2026. جودة مماثلة للنماذج المتقدمة بتكلفة أقل بكثير.", + "pricing.aiModels.essential.modelName": "نموذج الذكاء الاصطناعي الأساسي", + "pricing.aiModels.essential.context": "163K رمز سياقي", + "pricing.aiModels.essential.value": "قيمة ممتازة مقابل المال", + "pricing.aiModels.premium.title": "ترجمة AI متميزة", + "pricing.aiModels.premium.plan": "خطة Business", + "pricing.aiModels.premium.descPrefix": "مبني على", + "pricing.aiModels.premium.descSuffix": "من Anthropic — دقة عالية في المستندات القانونية والطبية والتقنية المعقدة.", + "pricing.aiModels.premium.context": "200K رمز سياقي", + "pricing.aiModels.premium.precision": "أعلى دقة", + "pricing.faq.title": "الأسئلة الشائعة", + "pricing.faq.q1": "هل يمكنني تغيير خطتي في أي وقت؟", + "pricing.faq.a1": "نعم. الترقية فورية ومُحاسب عليها بالتناسب. التخفيض يسري في نهاية الفترة الحالية.", + "pricing.faq.q2": "ما هي «ترجمة AI الأساسية»؟", + "pricing.faq.a2": "إنه محرك الذكاء الاصطناعي الخاص بنا. يفهم سياق مستنداتك، ويحافظ على التخطيط، ويتعامل مع المصطلحات التقنية بشكل أفضل بكثير من الترجمة الكلاسيكية.", + "pricing.faq.q3": "ما الفرق بين AI الأساسية وAI المتميزة؟", + "pricing.faq.a3": "الذكاء الاصطناعي الأساسي يستخدم نموذجًا محسّنًا (قيمة ممتازة مقابل المال). الذكاء الاصطناعي المتميز يستخدم Claude 3.5 Haiku من Anthropic، أكثر دقة في المستندات القانونية والطبية والتقنية المعقدة.", + "pricing.faq.q4": "هل تُحفظ مستنداتي بعد الترجمة؟", + "pricing.faq.a4": "الملفات المترجمة متاحة حسب خطتك (30 يومًا لـ Starter، 90 يومًا لـ Pro، سنة واحدة لـ Business). وهي مشفرة أثناء التخزين والنقل.", + "pricing.faq.q5": "ماذا يحدث إذا تجاوزت حصتي الشهرية؟", + "pricing.faq.a5": "يمكنك شراء أرصدة إضافية بشكل فردي أو ترقية خطتك. يتم إشعارك عند بلوغ 80% من الاستخدام.", + "pricing.faq.q6": "هل توجد فترة تجريبية مجانية للخطط المدفوعة؟", + "pricing.faq.a6": "الخطة المجانية دائمة ولا تتطلب بطاقة ائتمان. للخطط Pro و Business تواصل معنا للحصول على تجربة 14 يومًا.", + "pricing.faq.q7": "ما تنسيقات الملفات المدعومة؟", + "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx), and soon PDF. All plans support the same formats.", + "pricing.cta.title": "مستعد للبدء؟", + "pricing.cta.subtitle": "ابدأ مجانًا بدون بطاقة ائتمان. رقِّق عندما تحتاج.", + "pricing.cta.createAccount": "إنشاء حساب مجاني", + "pricing.cta.login": "تسجيل الدخول", + "pricing.toast.demo": "الوضع التجريبي — Stripe لم يُعدّ بعد. في بيئة الإنتاج سيتم توجيهك إلى الدفع لتفعيل خطة {planId}.", + "pricing.toast.networkError": "خطأ في الشبكة. يرجى إعادة المحاولة.", + "pricing.toast.paymentError": "خطأ أثناء إنشاء الدفع.", + "pricing.dashboard": "لوحة التحكم", + "pricing.okSymbol": "✓", + "pricing.errSymbol": "✕" +} diff --git a/frontend/src/lib/i18n/messages/ar/profile.json b/frontend/src/lib/i18n/messages/ar/profile.json new file mode 100644 index 0000000..c8eb276 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/profile.json @@ -0,0 +1,58 @@ +{ + "profile.header.title": "ملفي الشخصي", + "profile.header.subtitle": "إدارة حسابك وتفضيلاتك.", + "profile.tabs.account": "الحساب", + "profile.tabs.subscription": "الاشتراك", + "profile.tabs.preferences": "التفضيلات", + "profile.account.user": "المستخدم", + "profile.account.memberSince": "عضو منذ", + "profile.plan.label": "الخطة", + "profile.plan.free": "Free", + "profile.plan.starter": "Starter", + "profile.plan.pro": "Pro", + "profile.plan.business": "Business", + "profile.plan.enterprise": "Enterprise", + "profile.plan.pricePerMonth": "{price} €/شهر", + "profile.subscription.canceling": "جارٍ الإلغاء", + "profile.subscription.active": "نشط", + "profile.subscription.unknown": "غير معروف", + "profile.subscription.accessUntil": "الوصول حتى", + "profile.subscription.renewalOn": "التجديد في", + "profile.subscription.upgradePlan": "الترقية إلى خطة مدفوعة", + "profile.subscription.changePlan": "تغيير الخطة", + "profile.subscription.manageBilling": "إدارة الفوترة", + "profile.subscription.billingUnavailable": "بوابة الفوترة غير متاحة.", + "profile.subscription.billingError": "خطأ في الوصول إلى بوابة الفوترة.", + "profile.subscription.cancelSuccess": "تم إلغاء الاشتراك. تحتفظ بالوصول حتى نهاية الفترة.", + "profile.subscription.cancelError": "حدث خطأ أثناء الإلغاء.", + "profile.subscription.networkError": "خطأ في الشبكة.", + "profile.usage.title": "الاستخدام هذا الشهر", + "profile.usage.resetOn": "إعادة التعيين في", + "profile.usage.documents": "المستندات", + "profile.usage.pages": "الصفحات", + "profile.usage.extraCredits": "رصيد إضافي", + "profile.usage.extraCreditsPlural": "أرصدة إضافية", + "profile.usage.quotaReached": "تم بلوغ الحصة", + "profile.usage.quotaReachedDesc": "قم بالترقية إلى خطة أعلى للمتابعة.", + "profile.usage.unlockMore": "احصل على المزيد من الترجمات مع خطة مدفوعة.", + "profile.usage.viewPlans": "عرض الخطط", + "profile.usage.includedInPlan": "مضمن في خطتك", + "profile.danger.title": "منطقة الخطر", + "profile.danger.description": "يتم تطبيق الإلغاء في نهاية الفترة الحالية. تحتفظ بالوصول حتى ذلك التاريخ.", + "profile.danger.confirm": "هل أنت متأكد؟ لا يمكن التراجع عن هذا الإجراء.", + "profile.danger.confirmCancel": "تأكيد الإلغاء", + "profile.danger.cancelSubscription": "إلغاء اشتراكي", + "profile.danger.keep": "لا، إبقاء", + "profile.prefs.interfaceLang": "لغة الواجهة", + "profile.prefs.interfaceLangDesc": "يتم اكتشاف اللغة تلقائيًا بناءً على متصفحك. يمكنك تغييرها يدويًا.", + "profile.prefs.defaultTargetLang": "اللغة الهدف الافتراضية", + "profile.prefs.selectLanguage": "اختر لغة", + "profile.prefs.defaultTargetLangDesc": "سيتم تحديد هذه اللغة مسبقًا لترجماتك.", + "profile.prefs.save": "حفظ", + "profile.prefs.theme": "المظهر", + "profile.prefs.themeDesc": "اختر مظهر الواجهة", + "profile.prefs.cache": "ذاكرة التخزين المؤقت", + "profile.prefs.cacheDesc": "مسح ذاكرة التخزين المؤقت المحلية قد يحل بعض مشاكل العرض.", + "profile.prefs.clearing": "جارٍ المسح...", + "profile.prefs.clearCache": "مسح ذاكرة التخزين المؤقت" +} diff --git a/frontend/src/lib/i18n/messages/ar/providerSelector.json b/frontend/src/lib/i18n/messages/ar/providerSelector.json new file mode 100644 index 0000000..5c96b93 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/providerSelector.json @@ -0,0 +1,7 @@ +{ + "providerSelector.noClassic": "لا يوجد مترجم قياسي متاح.", + "providerSelector.noLlm": "لم يتم تكوين نموذج ذكاء اصطناعي.", + "providerSelector.costOne": "التكلفة: رصيد واحد لكل صفحة", + "providerSelector.costFive": "التكلفة: 5 أرصدة لكل صفحة (عامل مميز)", + "providerSelector.unlockContextual": "افتح الترجمة السياقية المتميزة لمستنداتك بالكامل." +} diff --git a/frontend/src/lib/i18n/messages/ar/providerTheme.json b/frontend/src/lib/i18n/messages/ar/providerTheme.json new file mode 100644 index 0000000..e5e4329 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/providerTheme.json @@ -0,0 +1,29 @@ +{ + "providerTheme.deepseek.badge": "أساسي", + "providerTheme.deepseek.subBadge": "تقني واقتصادي", + "providerTheme.deepseek.desc": "ترجمة فائقة الدقة واقتصادية، مثالية للمستندات التقنية والبرمجة.", + "providerTheme.openai.badge": "مميز", + "providerTheme.openai.subBadge": "دقة عالية", + "providerTheme.openai.desc": "معيار الذكاء الاصطناعي العالمي. أقصى اتساق نصي واحترام صارم للأسلوب.", + "providerTheme.minimax.badge": "متقدم", + "providerTheme.minimax.subBadge": "الأداء", + "providerTheme.minimax.desc": "سرعة تنفيذ مذهلة وفهم ممتاز للهياكل المعقدة.", + "providerTheme.openrouter.badge": "سريع", + "providerTheme.openrouter.subBadge": "متعدد النماذج", + "providerTheme.openrouter.desc": "وصول موحد إلى أفضل النماذج مفتوحة المصدر المحسّنة للترجمة.", + "providerTheme.openrouter_premium.badge": "فائق", + "providerTheme.openrouter_premium.subBadge": "السياق الأقصى", + "providerTheme.openrouter_premium.desc": "مدعوم من أحدث النماذج (GPT-4o، Claude Sonnet 4.6) للمستندات الطويلة.", + "providerTheme.zai.badge": "متخصص", + "providerTheme.zai.subBadge": "المال والقانون", + "providerTheme.zai.desc": "نموذج مضبوط بدقة للمصطلحات التجارية المتطلبة (قانونية، مالية).", + "providerTheme.default.badge": "حديث", + "providerTheme.default.subBadge": "تفكير الذكاء الاصطناعي", + "providerTheme.default.desc": "ترجمة بنموذج لغوي كبير (LLM) مع تحليل دلالي متقدم.", + "providerTheme.classic.google.label": "ترجمة Google", + "providerTheme.classic.google.desc": "ترجمة فائقة السرعة تغطي أكثر من 130 لغة. موصى بها للتدفقات العامة.", + "providerTheme.classic.deepl.label": "DeepL Pro", + "providerTheme.classic.deepl.desc": "ترجمة عالية الدقة مشهور بسيولتها وصياغاتها الطبيعية.", + "providerTheme.classic.google_cloud.label": "Google Cloud API", + "providerTheme.classic.google_cloud.desc": "محرك سحابي احترافي محسّن لمعالجة كميات كبيرة من المستندات." +} diff --git a/frontend/src/lib/i18n/messages/ar/register.json b/frontend/src/lib/i18n/messages/ar/register.json new file mode 100644 index 0000000..7bf586e --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/register.json @@ -0,0 +1,29 @@ +{ + "register.title": "إنشاء حساب", + "register.subtitle": "ابدأ الترجمة مجانًا", + "register.error.failed": "فشل التسجيل", + "register.name.label": "الاسم", + "register.name.placeholder": "اسمك", + "register.name.error": "يجب أن يحتوي الاسم على حرفين على الأقل", + "register.email.label": "البريد الإلكتروني", + "register.email.placeholder": "you@example.com", + "register.email.error": "عنوان بريد إلكتروني غير صالح", + "register.password.label": "كلمة المرور", + "register.password.error": "يجب أن تتكون كلمة المرور من 8 أحرف على الأقل، مع حرف كبير وحرف صغير ورقم", + "register.password.show": "إظهار كلمة المرور", + "register.password.hide": "إخفاء كلمة المرور", + "register.password.strengthLabel": "القوة:", + "register.password.strength.weak": "ضعيفة", + "register.password.strength.medium": "متوسطة", + "register.password.strength.strong": "قوية", + "register.confirmPassword.label": "تأكيد كلمة المرور", + "register.confirmPassword.error": "كلمتا المرور غير متطابقتين", + "register.confirmPassword.show": "إظهار", + "register.confirmPassword.hide": "إخفاء", + "register.submit.creating": "جارٍ إنشاء الحساب...", + "register.submit.create": "إنشاء حسابي", + "register.hasAccount": "لديك حساب بالفعل؟", + "register.login": "تسجيل الدخول", + "register.terms.prefix": "بإنشاء حساب، فإنك تقبل", + "register.terms.link": "شروط الخدمة الخاصة بنا" +} diff --git a/frontend/src/lib/i18n/messages/ar/services.json b/frontend/src/lib/i18n/messages/ar/services.json new file mode 100644 index 0000000..f49e10b --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/services.json @@ -0,0 +1,14 @@ +{ + "services.title": "مزودو الترجمة", + "services.subtitle": "تم تكوين المزودين من قبل المسؤول. يمكنك معرفة أيهم متاح حاليًا لحسابك.", + "services.loading": "جارٍ تحميل المزودين...", + "services.noProviders": "لا يوجد مزودون مكوّنون حاليًا. اتصل بالمسؤول.", + "services.classic": "ترجمة كلاسيكية", + "services.llmPro": "LLM · مدرك للسياق (Pro)", + "services.available": "متاح", + "services.model": "النموذج", + "services.adminOnly.title": "تكوين المزودين للمسؤولين فقط", + "services.adminOnly.desc": "يتم إدارة مفاتيح API واختيار النماذج وتفعيل المزودين حصريًا من قبل المسؤول في لوحة الإدارة. لا تحتاج أبدًا إلى إدخال مفتاح API.", + "services.fallback.google.label": "ترجمة Google", + "services.fallback.google.desc": "ترجمة سريعة، أكثر من 130 لغة" +} diff --git a/frontend/src/lib/i18n/messages/ar/settings.json b/frontend/src/lib/i18n/messages/ar/settings.json new file mode 100644 index 0000000..bdb8a20 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/settings.json @@ -0,0 +1,20 @@ +{ + "settings.title": "الإعدادات", + "settings.subtitle": "إعدادات التطبيق العامة", + "settings.formats.title": "التنسيقات المدعومة", + "settings.formats.subtitle": "أنواع المستندات التي يمكنك ترجمتها", + "settings.formats.formulas": "الصيغ", + "settings.formats.styles": "الأنماط", + "settings.formats.images": "الصور", + "settings.formats.headers": "الرؤوس", + "settings.formats.tables": "الجداول", + "settings.formats.slides": "الشرائح", + "settings.formats.notes": "الملاحظات", + "settings.cache.title": "ذاكرة التخزين المؤقت", + "settings.cache.desc": "مسح ذاكرة التخزين المؤقت المحلية قد يحل بعض مشاكل العرض.", + "settings.cache.clearing": "جارٍ المسح...", + "settings.cache.clear": "مسح ذاكرة التخزين المؤقت", + "settings.formats.excel.name": "Excel", + "settings.formats.word.name": "Word", + "settings.formats.powerpoint.name": "PowerPoint" +} diff --git a/frontend/src/lib/i18n/messages/ar/translate.json b/frontend/src/lib/i18n/messages/ar/translate.json new file mode 100644 index 0000000..cd54107 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/translate.json @@ -0,0 +1,92 @@ +{ + "translate.mode.label": "Mode de traduction", + "translate.mode.classic": "Classique", + "translate.mode.classicDesc": "Rapide", + "translate.mode.proLlm": "Pro LLM", + "translate.mode.proLlmDesc": "Contextuel", + "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", + "translate.mode.upgradeLink": "Passer à Pro", + "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", + "translate.glossary.title": "المسرد", + "translate.glossary.select": "اختر مسرداً", + "translate.glossary.none": "بدون", + "translate.glossary.terms": "مصطلحات", + "translate.glossary.proOnly": "قم بالترقية إلى Pro لاستخدام المصطلحات", + "translate.glossary.myGlossaries": "مصطلحاتي", + "translate.glossary.fromTemplate": "إنشاء من قالب", + "translate.glossary.noGlossaryForPair": "لا مصطلحات لـ", + "translate.glossary.noGlossaries": "لا مصطلحات", + "translate.glossary.loading": "جاري التحميل...", + "translate.glossary.classicMode": "محرك محايد بدون مسرد (AI فقط)", + "translate.glossary.selectPlaceholder": "اختر مسرداً...", + "translate.glossary.multilingual": "متعدد اللغات", + "translate.glossary.noGlossaryAvailable": "لا يوجد مسرد متاح", + "translate.glossary.filterByLang": "تصفية حسب اللغة", + "translate.glossary.active": "نشط", + "translate.glossary.inactive": "غير نشط", + "translate.glossary.availableTemplates": "القوالب المتاحة", + "translate.glossary.importing": "جاري الاستيراد...", + "translate.glossary.imported": "(مستورد)", + "translate.glossary.noGlossaryForSource": "لا يوجد مسرد أو قالب للغة المصدر", + "translate.glossary.createGlossary": "إنشاء مسرد", + "translate.glossary.showAll": "عرض جميع المسارد", + "translate.glossary.activePreview": "معاينة التطابقات النشطة:", + "translate.glossary.total": "الإجمالي", + "translate.glossary.moreTerms": "مصطلحات إضافية", + "translate.glossary.noTerms": "لا توجد مصطلحات في هذا المسرد.", + "translate.glossary.sourceTerm": "مصطلح المصدر", + "translate.glossary.translation": "الترجمة", + "translate.glossary.addTerm": "إضافة مصطلح", + "translate.glossary.disabledMode": "محرك محايد بدون مسرد مطبق", + "translate.glossary.addTermError": "خطأ في إضافة المصطلح", + "translate.glossary.networkError": "خطأ في الشبكة", + "translate.glossary.importFailed": "فشل الاستيراد ({status})", + "translate.glossary.helpText": "يسرد المسرد ترجمة دقيقة للمصطلحات. اختر مسرداً تطابق لغته المصدر اللغة الأصلية لمستندك.", + "translate.glossary.sourceWarning": "تحذير: هذا المسرد يستخدم لغة المصدر", + "translate.glossary.sourceWarningBut": "ولكن مستندك مهيأ بـ", + "translate.glossary.targetWarning": "عدم توافق الهدف: هذا المسرد مصمم للترجمة إلى", + "translate.glossary.targetWarningBut": "ولكن مستندك يستهدف", + "translate.glossary.targetWarningEnd": "قد لا تكون المصطلحات ذات صلة.", + "translate.header.processing": "جارٍ المعالجة", + "translate.header.aiActive": "تحليل الذكاء الاصطناعي نشط", + "translate.header.aiActiveDesc": "يتم الحفاظ على تخطيطك بواسطة محركنا السياقي.", + "translate.header.completed": "مكتمل", + "translate.header.completedTitle": "اكتملت الترجمة", + "translate.header.proSpace": "مساحة Pro", + "translate.header.translateDoc": "ترجمة مستند", + "translate.header.translateDocDesc": "حافظ على التخطيط الأصلي من خلال محرك الترجمة فائق الدقة.", + "translate.upload.nativeFormat": "التنسيق الأصلي", + "translate.fileType.word": "Word (.docx)", + "translate.fileType.excel": "Excel (.xlsx)", + "translate.fileType.slides": "شرائح (.pptx)", + "translate.fileType.pdf": "PDF (.pdf)", + "translate.startTranslation": "بدء الترجمة", + "translate.submit": "جارٍ الإرسال…", + "translate.chooseTargetLang": "يرجى اختيار لغة مستهدفة", + "translate.pleaseLoadFile": "يرجى تحميل ملف أولاً", + "translate.contextEngineActive": "المحرك السياقي نشط", + "translate.phase1": "المرحلة 1: التهيئة", + "translate.phase2": "المرحلة 2: إعادة البناء السياقي", + "translate.stat.segments": "مقاطع", + "translate.stat.precision": "الدقة", + "translate.stat.speedLabel": "السرعة", + "translate.stat.turbo": "تيربو", + "translate.stat.time": "الوقت", + "translate.complete.masterQuality": "✓ جودة رئيسية", + "translate.download": "تنزيل", + "translate.newTranslation": "+ ترجمة جديدة", + "translate.failedTitle": "خطأ في الترجمة", + "translate.retry": "إعادة المحاولة", + "translate.uploadAnother": "تحميل ملف آخر", + "translate.monitor": "مراقب الذكاء الاصطناعي", + "translate.summary": "ملخص", + "translate.cancelProcess": "⟳ إلغاء العملية", + "translate.layoutIntegrity": "سلامة التخطيط", + "translate.secureHundred": "100% آمن", + "translate.okHundred": "100% OK", + "translate.preserveLayout": "الحفاظ على التخطيط", + "translate.preserveLayoutDesc": "الحفاظ على التخطيط", + "translate.textOnly": "نص فقط", + "translate.textOnlyDesc": "ترجمة سريعة للنص فقط", + "translate.unavailableStandard": "غير متاح في الوضع القياسي (AI فقط)" +} diff --git a/frontend/src/lib/i18n/messages/ar/translateComplete.json b/frontend/src/lib/i18n/messages/ar/translateComplete.json new file mode 100644 index 0000000..b32196f --- /dev/null +++ b/frontend/src/lib/i18n/messages/ar/translateComplete.json @@ -0,0 +1,6 @@ +{ + "translateComplete.highQuality": "جودة عالية", + "translateComplete.segments": "المقاطع", + "translateComplete.characters": "الأحرف", + "translateComplete.confidence": "الثقة" +} diff --git a/frontend/src/lib/i18n/messages/de/admin.json b/frontend/src/lib/i18n/messages/de/admin.json new file mode 100644 index 0000000..9efbdd7 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/admin.json @@ -0,0 +1,48 @@ +{ + "admin.login.title": "Administration", + "admin.login.required": "Anmeldung erforderlich", + "admin.login.password": "Admin-Passwort", + "admin.login.connecting": "Verbindung wird hergestellt...", + "admin.login.access": "Admin-Panel öffnen", + "admin.login.restricted": "Nur für Administratoren", + "admin.layout.checking": "Authentifizierung wird überprüft...", + "admin.dashboard.title": "Admin-Dashboard", + "admin.dashboard.subtitle": "Administratorkontrollpanel", + "admin.dashboard.refresh": "Aktualisieren", + "admin.dashboard.refreshTooltip": "Dashboard-Daten aktualisieren", + "admin.dashboard.config": "Systemkonfiguration", + "admin.dashboard.maxFileSize": "Max. Dateigröße:", + "admin.dashboard.translationService": "Übersetzungsdienst:", + "admin.dashboard.formats": "Formate:", + "admin.nav.dashboard": "Dashboard", + "admin.nav.users": "Benutzer", + "admin.nav.pricing": "Preise & Stripe", + "admin.nav.providers": "Anbieter", + "admin.nav.system": "System", + "admin.nav.logs": "Protokolle", + "admin.users.title": "Benutzerverwaltung", + "admin.users.subtitle": "Benutzerkonten anzeigen und verwalten", + "admin.users.planUpdated": "Plan aktualisiert", + "admin.users.planChanged": "Der Plan wurde erfolgreich zu \\\"{plan}\\\" geändert.", + "admin.users.unknownError": "Unbekannter Fehler", + "admin.users.error": "Fehler", + "admin.users.planUpdateError": "Plan konnte nicht aktualisiert werden: {message}", + "admin.users.noKeys": "Keine Schlüssel", + "admin.users.noKeysDesc": "Dieser Benutzer hat keine aktiven API-Schlüssel.", + "admin.users.keysRevoked": "Schlüssel widerrufen", + "admin.users.keysRevokedDesc": "{count} API-Schlüssel erfolgreich widerrufen.", + "admin.users.revokeError": "Schlüssel konnten nicht widerrufen werden: {message}", + "admin.users.retry": "Erneut versuchen", + "admin.system.title": "System", + "admin.system.subtitle": "Systemstatus überwachen und Ressourcen verwalten", + "admin.system.quotas": "Übersetzungskontingente", + "admin.system.resetQuotas": "Monatliche Kontingente zurücksetzen", + "admin.system.resetting": "Zurücksetzen...", + "admin.system.reset": "Zurücksetzen", + "admin.system.allOperational": "Alle Systeme betriebsbereit", + "admin.system.issuesDetected": "Systemprobleme erkannt", + "admin.system.waitingData": "Warte auf Daten...", + "admin.system.purging": "Bereinigung läuft...", + "admin.system.clean": "Bereinigen", + "admin.system.purge": "Bereinigen" +} diff --git a/frontend/src/lib/i18n/messages/de/apiKeys.json b/frontend/src/lib/i18n/messages/de/apiKeys.json new file mode 100644 index 0000000..d6e3f04 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/apiKeys.json @@ -0,0 +1,72 @@ +{ + "apiKeys.webhook.title": "Intégration Webhook", + "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", + "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", + "apiKeys.webhook.codeParam": "webhook_url", + "apiKeys.title": "API-Schlüssel", + "apiKeys.subtitle": "Verwalten Sie Ihre API-Schlüssel für den programmgesteuerten Zugriff auf die Übersetzungs-API.", + "apiKeys.loading": "Laden...", + "apiKeys.sectionTitle": "API & Automatisierung", + "apiKeys.sectionDesc": "Generieren und verwalten Sie Ihre API-Schlüssel für Automatisierungs-Workflows", + "apiKeys.keysUsed": "{total} von {max} Schlüsseln verwendet", + "apiKeys.maxReached": "Maximale Anzahl an Schlüsseln erreicht. Widerrufen Sie einen Schlüssel, um einen neuen zu generieren.", + "apiKeys.canGenerate": "Sie können {count} weiteren Schlüssel generieren", + "apiKeys.canGeneratePlural": "Sie können {count} weitere Schlüssel generieren", + "apiKeys.generateNew": "Neuen Schlüssel generieren", + "apiKeys.keyRevoked": "Schlüssel widerrufen", + "apiKeys.keyRevokedDesc": "Der API-Schlüssel wurde erfolgreich widerrufen.", + "apiKeys.keyNotFound": "Schlüssel nicht gefunden", + "apiKeys.keyNotFoundDesc": "Der API-Schlüssel existiert nicht mehr. Er wurde möglicherweise bereits widerrufen.", + "apiKeys.error": "Fehler", + "apiKeys.revokeError": "Der API-Schlüssel konnte nicht widerrufen werden. Bitte versuchen Sie es erneut.", + "apiKeys.limitReached": "Limit erreicht", + "apiKeys.limitReachedDesc": "Sie haben das Maximum von 10 API-Schlüsseln erreicht. Widerrufen Sie einen vorhandenen Schlüssel, um einen neuen zu generieren.", + "apiKeys.proRequired": "Pro-Funktion erforderlich", + "apiKeys.proRequiredDesc": "API-Schlüssel sind eine Pro-Funktion. Bitte upgraden Sie Ihr Konto.", + "apiKeys.generateError": "API-Schlüssel konnte nicht generiert werden. Bitte versuchen Sie es erneut.", + "apiKeys.upgrade.title": "API-Schlüssel", + "apiKeys.upgrade.subtitle": "Automatisieren Sie Ihre Übersetzungen mit API-Zugang", + "apiKeys.upgrade.feat1": "Generieren Sie unbegrenzt API-Schlüssel", + "apiKeys.upgrade.feat2": "Automatisieren Sie die Dokumentübersetzung", + "apiKeys.upgrade.feat3": "Webhook-Benachrichtigungen", + "apiKeys.upgrade.feat4": "LLM-Übersetzungsmodi", + "apiKeys.upgrade.proFeature": "API-Schlüssel sind eine {pro}-Funktion. Upgraden Sie, um API-Automatisierung freizuschalten.", + "apiKeys.upgrade.pro": "Pro", + "apiKeys.upgrade.cta": "Auf Pro upgraden", + "apiKeys.dialog.maxTitle": "Maximale Anzahl an Schlüsseln erreicht", + "apiKeys.dialog.maxDesc": "Sie haben das Maximum von 10 API-Schlüsseln erreicht. Bitte widerrufen Sie einen vorhandenen Schlüssel, bevor Sie einen neuen generieren.", + "apiKeys.dialog.close": "Schließen", + "apiKeys.dialog.generated": "API-Schlüssel generiert!", + "apiKeys.dialog.generatedDesc": "Ihr neuer API-Schlüssel wurde erstellt. Kopieren Sie ihn jetzt – er wird nicht erneut angezeigt.", + "apiKeys.dialog.important": "Wichtig:", + "apiKeys.dialog.importantDesc": "Dies ist das einzige Mal, dass Sie diesen Schlüssel sehen. Speichern Sie ihn sicher.", + "apiKeys.dialog.apiKey": "API-Schlüssel", + "apiKeys.dialog.name": "Name:", + "apiKeys.dialog.done": "Fertig", + "apiKeys.dialog.copied": "Ich habe den Schlüssel kopiert", + "apiKeys.dialog.generateTitle": "Neuen API-Schlüssel generieren", + "apiKeys.dialog.generateDesc": "Erstellen Sie einen neuen API-Schlüssel für den programmgesteuerten Zugriff auf die Übersetzungs-API.", + "apiKeys.dialog.keyName": "Schlüsselname (optional)", + "apiKeys.dialog.keyNamePlaceholder": "z.B., Produktion, Staging", + "apiKeys.dialog.keyNameHint": "Ein beschreibender Name, um diesen Schlüssel später zu identifizieren.", + "apiKeys.dialog.nameTooLong": "Der Name muss {max} Zeichen oder weniger haben", + "apiKeys.dialog.nameInvalid": "Der Name darf nur Buchstaben, Zahlen, Leerzeichen, Bindestriche und Unterstriche enthalten", + "apiKeys.dialog.cancel": "Abbrechen", + "apiKeys.dialog.generating": "Wird generiert...", + "apiKeys.dialog.generate": "Schlüssel generieren", + "apiKeys.table.name": "Name", + "apiKeys.table.prefix": "Präfix", + "apiKeys.table.created": "Erstellt", + "apiKeys.table.lastUsed": "Zuletzt verwendet", + "apiKeys.table.never": "Nie", + "apiKeys.table.actions": "Aktionen", + "apiKeys.table.revoke": "Widerrufen", + "apiKeys.table.copyPrefix": "Schlüsselpräfix kopieren", + "apiKeys.table.revokeKey": "Schlüssel widerrufen", + "apiKeys.revokeDialog.title": "API-Schlüssel widerrufen", + "apiKeys.revokeDialog.desc": "Sind Sie sicher, dass Sie den Schlüssel \\\"{name}\\\" widerrufen möchten? Diese Aktion kann nicht rückgängig gemacht werden.", + "apiKeys.revokeDialog.confirm": "Ja, widerrufen", + "apiKeys.revokeDialog.cancel": "Abbrechen", + "apiKeys.noKeysGenerated": "Keine Schlüssel generiert", + "apiKeys.copied": "Kopiert!" +} diff --git a/frontend/src/lib/i18n/messages/de/auth.json b/frontend/src/lib/i18n/messages/de/auth.json new file mode 100644 index 0000000..b300370 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/auth.json @@ -0,0 +1,3 @@ +{ + "auth.brandName": "Wordly" +} diff --git a/frontend/src/lib/i18n/messages/de/checkout.json b/frontend/src/lib/i18n/messages/de/checkout.json new file mode 100644 index 0000000..5d0c6d1 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/checkout.json @@ -0,0 +1,12 @@ +{ + "checkout.activating": "Wird aktiviert…", + "checkout.activatingDesc": "Wir aktualisieren Ihr Abonnement, bitte warten Sie.", + "checkout.paymentConfirmed": "Zahlung bestätigt!", + "checkout.subscriptionActivated": "Abonnement aktiviert!", + "checkout.planActivated": "{plan}-Plan aktiviert!", + "checkout.redirectingToProfile": "Weiterleitung zu Ihrem Profil…", + "checkout.paymentReceived": "Zahlung erhalten", + "checkout.redirecting": "Weiterleitung…", + "checkout.syncError": "Synchronisierungsfehler", + "checkout.networkError": "Netzwerkfehler. Ihre Zahlung ist bestätigt — bitte laden Sie Ihr Profil neu." +} diff --git a/frontend/src/lib/i18n/messages/de/common.json b/frontend/src/lib/i18n/messages/de/common.json new file mode 100644 index 0000000..c13cf6b --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/common.json @@ -0,0 +1,4 @@ +{ + "common.loading": "Laden...", + "common.backToHome": "Zurück zur Startseite" +} diff --git a/frontend/src/lib/i18n/messages/de/context.json b/frontend/src/lib/i18n/messages/de/context.json new file mode 100644 index 0000000..ad00023 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/context.json @@ -0,0 +1,25 @@ +{ + "context.proTitle": "Pro-Funktion", + "context.proDesc": "Kontext und professionelle Glossare sind mit den Plänen Pro, Business und Enterprise verfügbar. Sie bieten genauere Übersetzungen durch Anweisungen und domänenspezifisches Vokabular.", + "context.viewPlans": "Pläne ansehen", + "context.title": "Kontext & Glossar", + "context.subtitle": "Verbessern Sie die Übersetzungsqualität mit Anweisungen und domänenspezifischem Vokabular.", + "context.presets.title": "Professionelle Glossare", + "context.presets.desc": "Laden Sie ein vollständiges Glossar mit Anweisungen und spezieller Terminologie", + "context.instructions.title": "Kontextanweisungen", + "context.instructions.desc": "Anweisungen, denen die KI während der Übersetzung folgt", + "context.instructions.placeholder": "Z.B.: Sie übersetzen HVAC-Fachdokumente. Verwenden Sie präzise Ingenieurterminologie...", + "context.glossary.title": "Technisches Glossar", + "context.glossary.desc": "Format: Quelle=Ziel (eines pro Zeile). Über Voreinstellung geladene Glossare sind bearbeitbar.", + "context.glossary.terms": "Begriffe im Glossar", + "context.clearAll": "Alles löschen", + "context.saving": "Wird gespeichert...", + "context.save": "Speichern", + "context.presets.createGlossary": "Glossar erstellen", + "context.presets.created": "Glossar erstellt", + "context.presets.createdDesc": "Das Glossar \\\"{name}\\\" wurde mit {count} Begriffen erstellt.", + "context.presets.hint": "Klicken Sie auf ein Preset, um ein Glossar mit domänenspezifischen Begriffen zu erstellen. Verwalten Sie Ihre Glossare im Glossar-Bereich.", + "context.glossary.manage": "Glossare verwalten", + "context.saved": "Gespeichert", + "context.savedDesc": "Ihre Kontextanweisungen wurden gespeichert." +} diff --git a/frontend/src/lib/i18n/messages/de/cookieConsent.json b/frontend/src/lib/i18n/messages/de/cookieConsent.json new file mode 100644 index 0000000..e348aca --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/cookieConsent.json @@ -0,0 +1,7 @@ +{ + "cookieConsent.title": "Cookies auf Wordly", + "cookieConsent.description": "Wir verwenden essenzielle Cookies, damit die App funktioniert (Sitzung, Sicherheit, Sprache). Mit Ihrer Erlaubnis verwenden wir auch optionale Cookies zur Verkehrsmessung und Produktverbesserung.", + "cookieConsent.acceptAll": "Alle akzeptieren", + "cookieConsent.essentialOnly": "Nur Essenzielle", + "cookieConsent.learnMore": "Mehr erfahren" +} diff --git a/frontend/src/lib/i18n/messages/de/dashboard.json b/frontend/src/lib/i18n/messages/de/dashboard.json new file mode 100644 index 0000000..036f7d8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/dashboard.json @@ -0,0 +1,111 @@ +{ + "dashboard.nav.translate": "Übersetzen", + "dashboard.nav.profile": "Mein Profil", + "dashboard.nav.settings": "Einstellungen", + "dashboard.nav.context": "Kontext", + "dashboard.nav.services": "Dienste", + "dashboard.nav.apiKeys": "API-Schlüssel", + "dashboard.nav.glossaries": "Glossare", + "dashboard.header.title": "Dashboard", + "dashboard.header.subtitle": "Verwalten Sie Ihre Übersetzungen", + "dashboard.header.toggleMenu": "Menü", + "dashboard.header.profileTitle": "Mein Profil", + "dashboard.sidebar.theme": "Design", + "dashboard.sidebar.signOut": "Abmelden", + "dashboard.sidebar.backHome": "Zurück zur Startseite", + "dashboard.sidebar.upgradeToPro": "Auf Pro upgraden →", + "dashboard.translate.pageTitle": "Dokument übersetzen", + "dashboard.translate.pageSubtitle": "Datei importieren und Zielsprache wählen", + "dashboard.translate.errorNotificationTitle": "Fehler", + "dashboard.translate.dropzone.uploadAria": "Datei-Ablagebereich", + "dashboard.translate.dropzone.title": "Datei hierher ziehen und ablegen", + "dashboard.translate.dropzone.subtitle": "oder klicken, um auszuwählen (DOCX, XLSX, PPTX, PDF)", + "dashboard.translate.dropzone.replaceFile": "Datei ersetzen", + "dashboard.translate.language.source": "Ausgangssprache", + "dashboard.translate.language.target": "Zielsprache", + "dashboard.translate.language.loading": "Sprachen werden geladen…", + "dashboard.translate.language.autoDetect": "Automatisch erkennen", + "dashboard.translate.language.selectPlaceholder": "Auswählen…", + "dashboard.translate.language.loadErrorPrefix": "Fehler beim Laden der Sprachen", + "dashboard.translate.provider.loading": "Anbieter werden geladen…", + "dashboard.translate.provider.noneConfigured": "Keine Anbieter konfiguriert", + "dashboard.translate.provider.modelTitle": "Modell", + "dashboard.translate.provider.sectionTitle": "Anbieter", + "dashboard.translate.provider.llmDivider": "KI · Kontextbasiert", + "dashboard.translate.provider.llmDividerPro": "KI · Kontextbasiert (Pro)", + "dashboard.translate.provider.upgrade": "Auf Pro upgraden", + "dashboard.translate.provider.upgradeSuffix": "um KI-Übersetzung freizuschalten", + "dashboard.translate.trust.zeroRetention": "Keine Datenspeicherung", + "dashboard.translate.trust.deletedAfter": "Dateien nach Verarbeitung gelöscht", + "dashboard.translate.actions.uploading": "Wird hochgeladen…", + "dashboard.translate.actions.translate": "Übersetzen", + "dashboard.translate.actions.filePrefix": "Datei: ", + "dashboard.translate.actions.cancel": "Abbrechen", + "dashboard.translate.actions.tryAgain": "Erneut versuchen", + "dashboard.translate.steps.uploading": "Datei wird hochgeladen…", + "dashboard.translate.steps.starting": "Übersetzung wird gestartet…", + "dashboard.translate.complete.title": "Übersetzung abgeschlossen!", + "dashboard.translate.complete.descNamed": "Ihre Datei {name} wurde erfolgreich übersetzt.", + "dashboard.translate.complete.descGeneric": "Ihre Datei wurde erfolgreich übersetzt.", + "dashboard.translate.complete.downloading": "Wird heruntergeladen…", + "dashboard.translate.complete.download": "Herunterladen", + "dashboard.translate.complete.newTranslation": "Neue Übersetzung", + "dashboard.translate.complete.toastOkTitle": "Erfolgreich", + "dashboard.translate.complete.toastOkDesc": "{name} wurde erfolgreich heruntergeladen.", + "dashboard.translate.complete.toastFailTitle": "Fehlgeschlagen", + "dashboard.translate.complete.toastFailDesc": "Übersetzung fehlgeschlagen. Bitte versuchen Sie es erneut.", + "dashboard.translate.sourceDocument": "Quelldokument", + "dashboard.translate.configuration": "Konfiguration", + "dashboard.translate.translating": "Übersetzung läuft", + "dashboard.translate.liveMonitor": "Live-Monitor", + "dashboard.translate.summary": "Zusammenfassung", + "dashboard.translate.engine": "Engine", + "dashboard.translate.confidence": "Konfidenz", + "dashboard.translate.cancel": "Abbrechen", + "dashboard.translate.segments": "Segmente", + "dashboard.translate.characters": "Zeichen", + "dashboard.translate.elapsed": "Verstrichen", + "dashboard.translate.segPerMin": "Seg/Min", + "dashboard.translate.highQuality": "Hohe Qualität", + "dashboard.translate.quality": "Qualität", + "dashboard.translate.completed": "Übersetzung abgeschlossen", + "dashboard.translate.replace": "Ersetzen", + "dashboard.translate.pdfMode.title": "PDF-Übersetzungsmodus", + "dashboard.translate.pdfMode.preserveLayout": "Layout beibehalten", + "dashboard.translate.pdfMode.textOnly": "Nur Text", + "dashboard.translate.pdfMode.preserveLayoutDesc": "Behält Bilder, Tabellen und Formatierung. Ideal für einfache PDFs.", + "dashboard.translate.pdfMode.textOnlyDesc": "Übersetzt den gesamten Text perfekt. Saubere Ausgabe ohne Layoutprobleme.", + "dashboard.translate.pipeline.upload": "Hochladen", + "dashboard.translate.pipeline.analyze": "Analysieren", + "dashboard.translate.pipeline.translate": "Übersetzung", + "dashboard.translate.pipeline.rebuild": "Rekonstruieren", + "dashboard.translate.pipeline.finalize": "Finalisieren", + "dashboard.translate.progress.processingFallback": "Verarbeitung läuft…", + "dashboard.translate.progress.connectionLost": "Verbindung verloren. Erneut versuchen…", + "dashboard.translate.progress.failedTitle": "Übersetzung fehlgeschlagen", + "dashboard.translate.error.unexpected": "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es erneut.", + "dashboard.translate.error.noResult": "Die Übersetzung hat keine Ergebnisse geliefert. Stellen Sie sicher, dass das Dokument Text enthält, und versuchen Sie es erneut oder wählen Sie eine andere Engine.", + "dashboard.translate.error.apiKey": "Ungültiger oder fehlender API-Schlüssel. Kontaktieren Sie den Administrator zur Konfiguration.", + "dashboard.translate.error.quota": "Nutzungslimit erreicht. Versuchen Sie es in wenigen Minuten erneut oder wählen Sie eine andere Engine.", + "dashboard.translate.error.timeout": "Verbindung zum Übersetzungsdienst zeitüberschritten. Prüfen Sie Ihr Netzwerk und versuchen Sie es erneut.", + "dashboard.translate.error.sessionExpired": "Sitzung abgelaufen. Klicken Sie auf Erneut versuchen, um die Übersetzung neu zu starten.", + "dashboard.translate.error.empty": "Das Dokument scheint leer zu sein oder enthält keinen übersetzbaren Text (eingescanntes PDF?).", + "dashboard.translate.error.unsupported": "Nicht unterstütztes Dateiformat oder beschädigte Datei.", + "dashboard.translate.error.connection": "Verbindung verloren. Prüfen Sie Ihr Netzwerk und versuchen Sie es erneut.", + "dashboard.translate.error.generic": "Übersetzung fehlgeschlagen: {detail}", + "dashboard.translate.error.title": "Übersetzung fehlgeschlagen", + "dashboard.translate.retry": "Übersetzung erneut versuchen", + "dashboard.translate.newFile": "Neue Datei", + "dashboard.translate.modeAI": "KI-Modus", + "dashboard.translate.modeClassic": "Klassischer Modus", + "dashboard.translate.glossaryLLMHint": "Glossare im KI-Modus verfügbar", + "dashboard.translate.submitting": "Wird gesendet...", + "dashboard.translate.submit": "Übersetzung starten", + "dashboard.translate.noFile": "Laden Sie zuerst eine Datei hoch", + "dashboard.translate.noTargetLang": "Wählen Sie eine Zielsprache", + "dashboard.topbar.interfaceLabel": "Übersetzungsoberfläche", + "dashboard.topbar.premiumAccess": "Premium-Zugang", + "dashboard.checkoutSyncError": "Fehler beim Synchronisieren der Zahlung.", + "dashboard.networkRefresh": "Netzwerkfehler. Bitte aktualisieren Sie die Seite.", + "dashboard.continueToTranslate": "Weiter zur Übersetzung" +} diff --git a/frontend/src/lib/i18n/messages/de/fileUploader.json b/frontend/src/lib/i18n/messages/de/fileUploader.json new file mode 100644 index 0000000..6774f0c --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/fileUploader.json @@ -0,0 +1,31 @@ +{ + "fileUploader.uploadDocument": "Dokument hochladen", + "fileUploader.uploadDesc": "Datei per Drag & Drop ablegen oder klicken (Excel, Word, PowerPoint)", + "fileUploader.dropHere": "Datei hier ablegen…", + "fileUploader.dragAndDrop": "Dokument hierher ziehen", + "fileUploader.orClickBrowse": "oder klicken Sie zum Durchsuchen", + "fileUploader.preview": "Vorschau", + "fileUploader.translationOptions": "Übersetzungsoptionen", + "fileUploader.configureSettings": "Übersetzungseinstellungen anpassen", + "fileUploader.targetLanguage": "Zielsprache", + "fileUploader.selectLanguage": "Sprache wählen", + "fileUploader.translationProvider": "Übersetzungsanbieter", + "fileUploader.selectProvider": "Anbieter wählen", + "fileUploader.advancedOptions": "Erweiterte Optionen", + "fileUploader.translateImages": "Bilder übersetzen", + "fileUploader.translating": "Übersetzung läuft…", + "fileUploader.translateDocument": "Dokument übersetzen", + "fileUploader.processing": "Verarbeitung…", + "fileUploader.translationError": "Übersetzungsfehler", + "fileUploader.translationComplete": "Übersetzung abgeschlossen!", + "fileUploader.translationCompleteDesc": "Ihr Dokument wurde erfolgreich übersetzt und die Formatierung beibehalten.", + "fileUploader.download": "Übersetztes Dokument herunterladen", + "fileUploader.webgpuUnsupported": "WebGPU wird in diesem Browser nicht unterstützt. Bitte verwenden Sie Chrome 113+ oder Edge 113+.", + "fileUploader.webllmNotLoaded": "WebLLM-Modell nicht geladen. Gehen Sie zu Einstellungen > Übersetzungsdienste, um ein Modell zu laden.", + "fileUploader.extracting": "Texte aus Dokument extrahieren…", + "fileUploader.noTranslatable": "Kein übersetzbarer Text im Dokument gefunden", + "fileUploader.foundTexts": "{count} zu übersetzende Texte gefunden", + "fileUploader.translatingItem": "Übersetze {current}/{total}: „{preview}\\\"", + "fileUploader.reconstructing": "Dokument wird rekonstruiert…", + "fileUploader.translatingLocally": "Lokale Übersetzung mit WebLLM…" +} diff --git a/frontend/src/lib/i18n/messages/de/forgotPassword.json b/frontend/src/lib/i18n/messages/de/forgotPassword.json new file mode 100644 index 0000000..0ac67c8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/forgotPassword.json @@ -0,0 +1,14 @@ +{ + "forgotPassword.enterEmail": "Please enter your email address", + "forgotPassword.error": "An error occurred", + "forgotPassword.title": "Forgot Password", + "forgotPassword.checkEmail": "Check your inbox", + "forgotPassword.subtitle": "Enter your email to receive a reset link", + "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", + "forgotPassword.emailLabel": "Email address", + "forgotPassword.emailPlaceholder": "you@example.com", + "forgotPassword.sending": "Sending...", + "forgotPassword.sendLink": "Send reset link", + "forgotPassword.backToLogin": "Back to login", + "forgotPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/de/glossaries.json b/frontend/src/lib/i18n/messages/de/glossaries.json new file mode 100644 index 0000000..3c5f28f --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/glossaries.json @@ -0,0 +1,189 @@ +{ + "glossaries.yourGlossaries": "Ihre Glossare", + "glossaries.title": "Glossare & Kontext", + "glossaries.description": "Verwalten Sie Ihre Glossare und Kontextanweisungen für genauere Übersetzungen.", + "glossaries.createNew": "Neu erstellen", + "glossaries.empty": "Noch keine Glossare", + "glossaries.emptyDesc": "Erstellen Sie Ihr erstes Glossar oder laden Sie eine professionelle Vorlage oben", + "glossaries.defineTerms": "Begriffe", + "glossaries.aboutTitle": "Über Glossare", + "glossaries.aboutDesc": "Glossare ermöglichen es Ihnen, exakte Übersetzungen für bestimmte Begriffe zu definieren. Bei der Übersetzung werden die Glossarbegriffe für konsistente und präzise Übersetzungen verwendet.", + "glossaries.aboutFormat": "Jeder Begriff hat ein Quellwort und Übersetzungen in mehreren Sprachen. Wählen Sie ein Glossar auf der Übersetzungsseite aus, um es anzuwenden.", + "glossaries.toast.created": "Glossar erstellt", + "glossaries.toast.createdDesc": "Das Glossar \\\"{name}\\\" wurde erstellt.", + "glossaries.toast.imported": "Glossar importiert", + "glossaries.toast.importedDesc": "Das Glossar \\\"{name}\\\" wurde importiert.", + "glossaries.toast.updated": "Glossar aktualisiert", + "glossaries.toast.updatedDesc": "Das Glossar \\\"{name}\\\" wurde aktualisiert.", + "glossaries.toast.deleted": "Glossar gelöscht", + "glossaries.toast.deletedDesc": "Das Glossar wurde gelöscht.", + "glossaries.toast.error": "Fehler", + "glossaries.toast.errorCreate": "Glossar konnte nicht erstellt werden", + "glossaries.toast.errorImport": "Glossar konnte nicht importiert werden", + "glossaries.toast.errorUpdate": "Glossar konnte nicht aktualisiert werden", + "glossaries.toast.errorDelete": "Glossar konnte nicht gelöscht werden", + "glossaries.dialog.title": "Neues Glossar", + "glossaries.dialog.description": "Erstellen Sie ein Glossar für Ihre Übersetzungen", + "glossaries.dialog.nameLabel": "Name", + "glossaries.dialog.namePlaceholder": "Mein Glossar", + "glossaries.dialog.tabTemplates": "Vorlagen", + "glossaries.dialog.tabFile": "Datei", + "glossaries.dialog.tabManual": "Manuell", + "glossaries.dialog.cancel": "Abbrechen", + "glossaries.dialog.creating": "Wird erstellt…", + "glossaries.dialog.importing": "Wird importiert…", + "glossaries.dialog.importBtn": "Importieren", + "glossaries.dialog.selectPrompt": "Auswählen", + "glossaries.dialog.createBtn": "Erstellen", + "glossaries.dialog.createEmpty": "Leer erstellen", + "glossaries.dialog.terms": "Begriffe", + "glossaries.dialog.templatesDesc": "Wählen Sie eine vordefinierte Vorlage", + "glossaries.dialog.templatesEmpty": "Keine Vorlagen verfügbar", + "glossaries.dialog.dropTitle": "CSV-Datei hierher ziehen", + "glossaries.dialog.dropOr": "oder", + "glossaries.dialog.dropFormats": "CSV, TSV, TXT", + "glossaries.termEditor.addTerm": "Begriff hinzufügen", + "glossaries.termEditor.maxReached": "Maximal {max} Begriffe pro Glossar erreicht.", + "glossaries.dialog.formatTitle": "Format", + "glossaries.dialog.formatDesc": "Quelle,Ziel (eine pro Zeile)", + "glossaries.dialog.formatNote": "Erste Zeile wird bei erkanntem Header übersprungen", + "glossaries.dialog.errorFormat": "Nicht unterstütztes Format", + "glossaries.dialog.errorSize": "Datei zu groß", + "glossaries.dialog.errorEmpty": "Leere Datei", + "glossaries.dialog.errorRead": "Lesefehler", + "glossaries.dialog.parsing": "Wird analysiert…", + "glossaries.dialog.termsImported": "Begriffe importiert", + "glossaries.dialog.changeFile": "Datei ändern", + "glossaries.dialog.retry": "Erneut versuchen", + "glossaries.edit.title": "Modifier le glossaire", + "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", + "glossaries.edit.nameLabel": "Nom du glossaire", + "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", + "glossaries.edit.sourceLang": "Langue source", + "glossaries.edit.targetLang": "Langue cible", + "glossaries.edit.termsLabel": "Termes ({count} valides)", + "glossaries.edit.exportCsv": "Exporter CSV", + "glossaries.edit.importCsv": "Importer CSV", + "glossaries.edit.cancel": "Annuler", + "glossaries.edit.saving": "Enregistrement...", + "glossaries.edit.saveChanges": "Enregistrer les modifications", + "glossaries.edit.importFailedTitle": "Échec de l'importation", + "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", + "glossaries.edit.importSuccessTitle": "Importation réussie", + "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", + "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", + "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", + "glossaries.delete.title": "Supprimer le glossaire", + "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", + "glossaries.delete.warning": "Cette action est irréversible", + "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", + "glossaries.delete.cancel": "Annuler", + "glossaries.delete.deleting": "Suppression...", + "glossaries.delete.deleteBtn": "Supprimer", + "glossaries.upgrade.title": "Glossaires", + "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", + "glossaries.upgrade.feature1": "Créez plusieurs glossaires", + "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", + "glossaries.upgrade.feature3": "Importez/exportez via CSV", + "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", + "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", + "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", + "glossaries.upgrade.proLabel": "Pro", + "glossaries.upgrade.upgradeBtn": "Passer à Pro", + "glossaries.loading": "Chargement...", + "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", + "glossaries.howItWorks.step1Title": "Configurez ici", + "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", + "glossaries.howItWorks.step2Title": "Activez dans Traduire", + "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", + "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", + "glossaries.howItWorks.goToTranslate": "Aller à Traduire", + "glossaries.status.unsaved": "Non enregistré", + "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", + "glossaries.status.inactive": "Inactif", + "glossaries.instructions.whatForBold": "À quoi ça sert ?", + "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", + "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", + "glossaries.instructions.charCount": "{count} caractères", + "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", + "glossaries.instructions.clearAll": "Tout effacer", + "glossaries.instructions.saving": "Enregistrement…", + "glossaries.instructions.saved": "Enregistré", + "glossaries.presets.whatForBold": "À quoi ça sert ?", + "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", + "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", + "glossaries.presets.creating": "Création…", + "glossaries.presets.alreadyImported": "Déjà importé", + "glossaries.presets.it.title": "IT / Logiciel", + "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", + "glossaries.presets.legal.title": "Juridique / Contrats", + "glossaries.presets.legal.desc": "Droit des affaires, contentieux", + "glossaries.presets.medical.title": "Médical / Santé", + "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", + "glossaries.presets.finance.title": "Finance / Comptabilité", + "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", + "glossaries.presets.marketing.title": "Marketing / Publicité", + "glossaries.presets.marketing.desc": "Digital, branding, analytics", + "glossaries.presets.hr.title": "RH / Ressources Humaines", + "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", + "glossaries.presets.scientific.title": "Scientifique / Recherche", + "glossaries.presets.scientific.desc": "Publications, thèses, articles", + "glossaries.presets.ecommerce.title": "E-commerce / Vente", + "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", + "glossaries.grid.title": "Vos", + "glossaries.grid.titleHighlight": "glossaires", + "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", + "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", + "glossaries.grid.activeTranslation": "Traduction active :", + "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", + "glossaries.badge.compatible": "Compatible", + "glossaries.badge.otherTarget": "Autre cible", + "glossaries.card.editTerms": "Modifier les termes", + "glossaries.card.created": "Erstellt", + "glossaries.card.term": "Begriff", + "glossaries.card.delete": "Supprimer", + "glossaries.grid.searchPlaceholder": "Search a glossary…", + "glossaries.grid.noResults": "No results for this search.", + "glossaries.detail.backToList": "Back to glossaries", + "glossaries.detail.save": "Save", + "glossaries.detail.savedTitle": "Saved", + "glossaries.detail.savedDesc": "The glossary has been updated.", + "glossaries.detail.settingsTitle": "Settings", + "glossaries.detail.sourceLang": "Source language", + "glossaries.detail.targetLang": "Target language", + "glossaries.detail.termsTitle": "Terms", + "glossaries.detail.terms": "terms", + "glossaries.detail.searchTerms": "Filter…", + "glossaries.detail.noTerms": "No terms yet.", + "glossaries.detail.addFirstTerm": "Add the first term", + "glossaries.detail.addTerm": "Add a term", + "glossaries.detail.maxReached": "Maximum limit reached", + "glossaries.detail.source": "Source", + "glossaries.detail.target": "Target", + "glossaries.detail.sourcePlaceholder": "source term", + "glossaries.detail.targetPlaceholder": "target term", + "glossaries.detail.csvTitle": "CSV", + "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", + "glossaries.detail.export": "Export", + "glossaries.detail.import": "Import", + "glossaries.detail.dangerTitle": "Danger zone", + "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", + "glossaries.detail.deleteGlossary": "Delete this glossary", + "glossaries.detail.confirmDelete": "Confirm deletion?", + "glossaries.detail.confirm": "Confirm", + "glossaries.detail.cancel": "Cancel", + "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", + "glossaries.detail.sourceLocked": "fixed", + "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", + "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", + "glossaries.detail.notFoundTitle": "Glossary not found", + "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", + "glossaries.detail.maxTermsTitle": "Limit reached", + "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", + "glossaries.detail.importEmptyTitle": "Empty file", + "glossaries.detail.importEmptyDesc": "No terms detected in this file.", + "glossaries.detail.importedTitle": "Imported", + "glossaries.detail.importedDesc": "{count} terms imported.", + "glossaries.detail.importErrorTitle": "Read error", + "glossaries.detail.importErrorDesc": "Unable to read the file." +} diff --git a/frontend/src/lib/i18n/messages/de/index.ts b/frontend/src/lib/i18n/messages/de/index.ts new file mode 100644 index 0000000..b8b2ec9 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/index.ts @@ -0,0 +1,60 @@ +// Auto-generated by scripts/generate_i18n_index.py +// Merges all namespace JSON files for locale "de". + +import admin from "./admin.json"; +import apiKeys from "./apiKeys.json"; +import auth from "./auth.json"; +import checkout from "./checkout.json"; +import common from "./common.json"; +import context from "./context.json"; +import cookieConsent from "./cookieConsent.json"; +import dashboard from "./dashboard.json"; +import fileUploader from "./fileUploader.json"; +import forgotPassword from "./forgotPassword.json"; +import glossaries from "./glossaries.json"; +import landing from "./landing.json"; +import langSelector from "./langSelector.json"; +import layout from "./layout.json"; +import login from "./login.json"; +import memento from "./memento.json"; +import pricing from "./pricing.json"; +import profile from "./profile.json"; +import providerSelector from "./providerSelector.json"; +import providerTheme from "./providerTheme.json"; +import register from "./register.json"; +import resetPassword from "./resetPassword.json"; +import services from "./services.json"; +import settings from "./settings.json"; +import translate from "./translate.json"; +import translateComplete from "./translateComplete.json"; + +const messages: Record = { + ...admin, + ...apiKeys, + ...auth, + ...checkout, + ...common, + ...context, + ...cookieConsent, + ...dashboard, + ...fileUploader, + ...forgotPassword, + ...glossaries, + ...landing, + ...langSelector, + ...layout, + ...login, + ...memento, + ...pricing, + ...profile, + ...providerSelector, + ...providerTheme, + ...register, + ...resetPassword, + ...services, + ...settings, + ...translate, + ...translateComplete, +}; + +export default messages; diff --git a/frontend/src/lib/i18n/messages/de/landing.json b/frontend/src/lib/i18n/messages/de/landing.json new file mode 100644 index 0000000..0ba64b3 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/landing.json @@ -0,0 +1,146 @@ +{ + "landing.nav.why": "Warum wir?", + "landing.nav.formats": "Formate", + "landing.nav.pricing": "Preise", + "landing.nav.login": "Anmelden", + "landing.nav.startFree": "Kostenlos starten", + "landing.hero.tag": "Professionelle Dokument-KI", + "landing.hero.titleLine1": "Übersetzen Sie Ihre Dokumente.", + "landing.hero.titleLine2": "Mit perfekter Formatierung.", + "landing.hero.description": "Der einzige Übersetzer, der SmartArt, Diagramme, Inhaltsverzeichnisse, Formen und komplexe Layouts bewahrt — genau wie im Original.", + "landing.hero.ctaMain": "Kostenlos starten — 2 Docs/Monat", + "landing.hero.ctaSec": "Angebote sehen", + "landing.hero.deleted": "Dateien nach 60 Min. gelöscht", + "landing.hero.noHidden": "Keine versteckten Gebühren", + "landing.hero.preview": "Vorschau vor Bezahlung", + "landing.hero.formattedOk": "Formatierung OK", + "landing.hero.aiActive": "KI-Übersetzung aktiv", + "landing.steps.title": "Wie funktioniert es?", + "landing.steps.subtitle": "Drei Schritte. Kein Formatverlust.", + "landing.steps.step1.num": "01", + "landing.steps.step1.title": "Datei hochladen", + "landing.steps.step1.desc": "Drag & Drop Ihres Excel-, Word-, PowerPoint- oder PDF-Dokuments.", + "landing.steps.step2.num": "02", + "landing.steps.step2.title": "Sprache & Engine wählen", + "landing.steps.step2.desc": "Zielsprache und Engine auswählen — klassisch oder kontextbewusste KI.", + "landing.steps.step3.num": "03", + "landing.steps.step3.title": "Ergebnis herunterladen", + "landing.steps.step3.desc": "Erhalten Sie Ihr übersetztes Dokument mit identischer Formatierung wie das Original.", + "landing.features.tag": "KI-Übersetzungsengine", + "landing.features.title": "Übersetzung, die Ihr Handwerk versteht", + "landing.features.description": "Unsere KI-Modelle analysieren den Kontext, respektieren Ihre Terminologie und übersetzen sogar Text in Bildern.", + "landing.features.context.title": "Branchenkontext", + "landing.features.context.desc": "Beschreiben Sie Ihr Fachgebiet und erhalten Sie maßgeschneiderte Übersetzungen — nicht generische.", + "landing.features.glossary.title": "Fachglossare", + "landing.features.glossary.desc": "Definieren Sie Ihre Fachbegriffe. CTA bleibt «Luftbehandlungsanlage», nie «Call To Action».", + "landing.features.vision.title": "Bilderkennung", + "landing.features.vision.desc": "Text in Bildern, Diagrammen und Grafiken wird erkannt und übersetzt.", + "landing.features.demo.source": "Quelle (FR)", + "landing.features.demo.google": "Google Translate", + "landing.features.demo.ours": "Unsere KI", + "landing.layout.title": "Ihre Formatierung,", + "landing.layout.title2": "perfekt erhalten", + "landing.layout.subtitle": "Andere Übersetzer zerstören Ihr Layout. Wir nicht.", + "landing.layout.p1.title": "SmartArt & Diagramme", + "landing.layout.p1.desc": "Organigramme, Flussdiagramme, Hierarchien — alles identisch übersetzt.", + "landing.layout.p2.title": "Inhaltsverzeichnisse", + "landing.layout.p2.desc": "Inhaltsverzeichniseinträge, Seitenzahlen und Querverweise korrekt aktualisiert.", + "landing.layout.p3.title": "Diagramme & Grafiken", + "landing.layout.p3.desc": "Titel, Achsenbeschriftungen, Legenden und Reihennamen — alles übersetzt.", + "landing.layout.p4.title": "Formen & Textfelder", + "landing.layout.p4.desc": "Rechtecke, abgerundete Blöcke, Legenden — überall lokalisiert.", + "landing.layout.p5.title": "Kopf- & Fußzeilen", + "landing.layout.p5.desc": "Kopfzeilen, Fußzeilen und Fußnoten werden nie übersehen.", + "landing.layout.p6.title": "130+ Sprachen", + "landing.layout.p6.desc": "Google Translate, DeepL und professionelle KI-Engines.", + "landing.formats.title": "Jedes Format,", + "landing.formats.title2": "jedes Element", + "landing.formats.subtitle": "Wir übersetzen, was andere vergessen. Ihr Unternehmen verdient einwandfreie Dokumentation.", + "landing.formats.word.name": "Word", + "landing.formats.word.i1": "Absätze und Überschriften", + "landing.formats.word.i2": "Tabellen und Diagramme", + "landing.formats.word.i3": "SmartArt-Diagramme", + "landing.formats.word.i4": "Inhaltsverzeichnis", + "landing.formats.word.i5": "Kopf- und Fußzeilen", + "landing.formats.word.i6": "Formen und Textfelder", + "landing.formats.word.i7": "Fuß- und Endnoten", + "landing.formats.excel.name": "Excel", + "landing.formats.excel.i1": "Zellwerte", + "landing.formats.excel.i2": "Blattnamen", + "landing.formats.excel.i3": "Diagramme und Beschriftungen", + "landing.formats.excel.i4": "Kopf- und Fußzeilen", + "landing.formats.excel.i5": "Verbundene Zellen erhalten", + "landing.formats.pptx.name": "PowerPoint", + "landing.formats.pptx.i1": "Folientext und Notizen", + "landing.formats.pptx.i2": "Diagramme und Grafiken", + "landing.formats.pptx.i3": "Formen und Textfelder", + "landing.formats.pptx.i4": "Folienmaster", + "landing.formats.pptx.i5": "Animationen erhalten", + "landing.formats.pdf.name": "PDF", + "landing.formats.pdf.i1": "Textbasierte PDFs", + "landing.formats.pdf.i2": "Layout erhalten", + "landing.formats.pdf.i3": "Bilder an Ort und Stelle", + "landing.formats.pdf.i4": "Tabellen beibehalten", + "landing.formats.pdf.i5": "Ausgabe als DOCX oder PDF", + "landing.pricing.title": "Einfache, ehrliche Preise", + "landing.pricing.subtitle": "Was Sie sehen, ist was Sie zahlen. Keine versteckten Gebühren.", + "landing.pricing.monthly": "Monatlich", + "landing.pricing.annual": "Jährlich", + "landing.pricing.bestValue": "Am beliebtesten", + "landing.pricing.month": "/Monat", + "landing.pricing.footer": "Der angezeigte Preis ist der Preis, den Sie zahlen. Keine versteckten Gebühren nach der Übersetzung.", + "landing.pricing.starter.name": "Starter", + "landing.pricing.starter.desc": "Für Einzelpersonen und kleine Projekte", + "landing.pricing.starter.f1": "50 Dokumente / Monat", + "landing.pricing.starter.f2": "Bis zu 50 Seiten pro Dokument", + "landing.pricing.starter.f3": "Google Translate + DeepL", + "landing.pricing.starter.f4": "Dateien bis zu 10 MB", + "landing.pricing.starter.cta": "Loslegen", + "landing.pricing.pro.name": "Pro", + "landing.pricing.pro.desc": "Für anspruchsvolle Profis", + "landing.pricing.pro.f1": "200 Dokumente / Monat", + "landing.pricing.pro.f2": "Bis zu 200 Seiten pro Dokument", + "landing.pricing.pro.f3": "KI-gestützte Übersetzung", + "landing.pricing.pro.f4": "Google + DeepL inklusive", + "landing.pricing.pro.f5": "Individuelle Glossare & Prompts", + "landing.pricing.pro.f6": "Prioritäts-Support", + "landing.pricing.pro.cta": "Pro testen", + "landing.pricing.business.name": "Business", + "landing.pricing.business.desc": "Für Teams mit hohem Bedarf", + "landing.pricing.business.f1": "1 000 Dokumente / Monat", + "landing.pricing.business.f2": "Bis zu 500 Seiten pro Dokument", + "landing.pricing.business.f3": "Premium-KI (Claude)", + "landing.pricing.business.f4": "Alle Anbieter + API-Zugang", + "landing.pricing.business.f5": "Webhooks & Automatisierung", + "landing.pricing.business.f6": "5 Teamplätze", + "landing.pricing.business.cta": "Kontaktieren Sie uns", + "landing.cta.title": "In 30 Sekunden mit der Übersetzung beginnen", + "landing.cta.subtitle": "Keine Kreditkarte erforderlich. Probieren Sie es jetzt kostenlos und erwecken Sie Ihre mehrsprachigen Dokumente zum Leben.", + "landing.cta.button": "Kostenloses Konto erstellen", + "landing.cta.secure": "Geschützt durch AES-256-Verschlüsselung", + "landing.footer.desc": "Experte für intelligente Dokumentenübersetzung. Wir verbinden die Kunst des Layouts mit der Wissenschaft kontextbezogener KI.", + "landing.footer.product": "Produkt", + "landing.footer.resources": "Ressourcen", + "landing.footer.legal": "Rechtliches", + "landing.footer.rights": "© 2026 Wordly.art — Alle Rechte vorbehalten.", + "landing.hero.contextEngine": "Übersetzung erkannt: Technischer Wartungsbegriff für HVAC-Systeme...", + "landing.hero.liveAnalysis": "Live-Analyse", + "landing.hero.termsDetected": "Begriffe erkannt", + "landing.steps.process": "PROZESS", + "landing.translate.newProject": "Neues Projekt", + "landing.translate.title": "Dokument übersetzen", + "landing.translate.subtitle": "Datei importieren und Zielsprache wählen", + "landing.translate.sourceDocument": "Quelldokument", + "landing.translate.configuration": "Konfiguration", + "landing.translate.sourceLang": "Quellsprache", + "landing.translate.targetLang": "Zielsprache", + "landing.translate.provider": "Anbieter", + "landing.translate.startTranslation": "Übersetzung starten", + "landing.translate.zeroRetention": "Keine Speicherung", + "landing.translate.filesDeleted": "Dateien nach Verarbeitung gelöscht", + "landing.translate.dropHere": "Hier ablegen", + "landing.translate.supportedFormats": "DOCX, XLSX, PPTX oder PDF Dateien unterstützt", + "landing.translate.aiAnalysis": "KI-Analyse aktiv", + "landing.translate.processing": "Verarbeitung läuft", + "landing.translate.preservingLayout": "Ihr Layout wird beibehalten" +} diff --git a/frontend/src/lib/i18n/messages/de/langSelector.json b/frontend/src/lib/i18n/messages/de/langSelector.json new file mode 100644 index 0000000..4c82b50 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/langSelector.json @@ -0,0 +1,7 @@ +{ + "langSelector.search": "Suchen…", + "langSelector.noResults": "Keine Ergebnisse", + "langSelector.source": "Quelle", + "langSelector.target": "Ziel", + "langSelector.swap": "Tauschen" +} diff --git a/frontend/src/lib/i18n/messages/de/layout.json b/frontend/src/lib/i18n/messages/de/layout.json new file mode 100644 index 0000000..e4516d9 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/layout.json @@ -0,0 +1,5 @@ +{ + "layout.nav.apiAccess": "API-Zugang", + "layout.footer.terms": "AGB", + "layout.footer.privacy": "Datenschutz" +} diff --git a/frontend/src/lib/i18n/messages/de/login.json b/frontend/src/lib/i18n/messages/de/login.json new file mode 100644 index 0000000..57cd20d --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/login.json @@ -0,0 +1,18 @@ +{ + "login.errorTitle": "Login Error", + "login.welcomeBack": "Welcome back", + "login.signInToContinue": "Sign in to continue translating", + "login.email": "Email", + "login.emailPlaceholder": "you@example.com", + "login.password": "Password", + "login.forgotPassword": "Forgot password?", + "login.passwordPlaceholder": "••••••••", + "login.signingIn": "Signing in...", + "login.signIn": "Sign In", + "login.noAccount": "Don't have an account?", + "login.signUpFree": "Sign up for free", + "login.orContinueWith": "oder mit E-Mail fortfahren", + "login.google.connecting": "Verbinden…", + "login.google.errorGeneric": "Bei der Google-Anmeldung ist ein Fehler aufgetreten.", + "login.google.errorFailed": "Google-Anmeldung fehlgeschlagen. Bitte erneut versuchen." +} diff --git a/frontend/src/lib/i18n/messages/de/memento.json b/frontend/src/lib/i18n/messages/de/memento.json new file mode 100644 index 0000000..efa0027 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/memento.json @@ -0,0 +1,6 @@ +{ + "memento.title": "Entdecken Sie Momento", + "memento.slogan": "Momento ist mehr als nur eine Notizen-App. Es ist ein intelligentes Ökosystem, das Ihre Ideen in Echtzeit verbindet, analysiert und weiterentwickelt – mit 6 KI-Agenten und semantischer Suche.", + "memento.ctaFree": "Kostenlos starten", + "memento.ctaMore": "Mehr erfahren" +} diff --git a/frontend/src/lib/i18n/messages/de/pricing.json b/frontend/src/lib/i18n/messages/de/pricing.json new file mode 100644 index 0000000..1976675 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/pricing.json @@ -0,0 +1,151 @@ +{ + "pricing.nav.back": "Zurück", + "pricing.nav.home": "Startseite", + "pricing.nav.mySubscription": "Mein Abonnement", + "pricing.header.badge": "KI-Modelle aktualisiert — März 2026", + "pricing.header.title": "Der passende Plan für jedes Bedürfnis", + "pricing.header.subtitle": "Übersetzen Sie Ihre Word-, Excel- und PowerPoint-Dokumente unter Beibehaltung des Original-Layouts. Ohne API-Schlüssel.", + "pricing.billing.monthly": "Monatlich", + "pricing.billing.yearly": "Jährlich", + "pricing.plans.free.name": "Kostenlos", + "pricing.plans.starter.name": "Starter", + "pricing.plans.pro.name": "Pro", + "pricing.plans.business.name": "Business", + "pricing.plans.enterprise.name": "Enterprise", + "pricing.plans.free.description": "Perfekt zum Kennenlernen der App", + "pricing.plans.starter.description": "Für Einzelpersonen und kleine Projekte", + "pricing.plans.pro.description": "Für Professionals und wachsende Teams", + "pricing.plans.business.description": "Für Teams und Organisationen", + "pricing.plans.enterprise.description": "Maßgeschneiderte Lösungen für große Organisationen", + "pricing.plans.pro.highlight": "Am beliebtesten", + "pricing.plans.pro.badge": "BELIEBT", + "pricing.plans.enterprise.badge": "AUF ANFRAGE", + "pricing.plans.free.feat1": "5 Dokumente / Monat", + "pricing.plans.free.feat2": "Bis zu 15 Seiten pro Dokument", + "pricing.plans.free.feat3": "Google Übersetzer inklusive", + "pricing.plans.free.feat4": "Alle Sprachen (130+)", + "pricing.plans.free.feat5": "Community-Support", + "pricing.plans.starter.feat1": "50 Dokumente / Monat", + "pricing.plans.starter.feat2": "Bis zu 50 Seiten pro Dokument", + "pricing.plans.starter.feat3": "Google Übersetzer + DeepL", + "pricing.plans.starter.feat4": "Dateien bis zu 10 MB", + "pricing.plans.starter.feat5": "E-Mail-Support", + "pricing.plans.starter.feat6": "30 Tage Verlauf", + "pricing.plans.pro.feat1": "200 Dokumente / Monat", + "pricing.plans.pro.feat2": "Bis zu 200 Seiten pro Dokument", + "pricing.plans.pro.feat3": "KI-Basisübersetzung", + "pricing.plans.pro.feat4": "Google Übersetzer + DeepL", + "pricing.plans.pro.feat5": "Dateien bis zu 25 MB", + "pricing.plans.pro.feat6": "Benutzerdefinierte Glossare", + "pricing.plans.pro.feat7": "Prioritäts-Support", + "pricing.plans.pro.feat8": "90 Tage Verlauf", + "pricing.plans.business.feat1": "1.000 Dokumente / Monat", + "pricing.plans.business.feat2": "Bis zu 500 Seiten pro Dokument", + "pricing.plans.business.feat3": "Basis- + Premium-KI (Claude Haiku)", + "pricing.plans.business.feat4": "Alle Übersetzungsanbieter", + "pricing.plans.business.feat5": "Dateien bis zu 50 MB", + "pricing.plans.business.feat6": "API-Zugang (10.000 Aufrufe/Monat)", + "pricing.plans.business.feat7": "Benachrichtigungs-Webhooks", + "pricing.plans.business.feat8": "Dedizierter Support", + "pricing.plans.business.feat9": "1 Jahr Verlauf", + "pricing.plans.business.feat10": "Erweiterte Analysen", + "pricing.plans.enterprise.feat1": "Unbegrenzte Dokumente", + "pricing.plans.enterprise.feat2": "Alle KI-Modelle (GPT-5, Claude Opus 4.6…)", + "pricing.plans.enterprise.feat3": "On-Premise oder dedizierte Cloud", + "pricing.plans.enterprise.feat4": "99,9 % SLA garantiert", + "pricing.plans.enterprise.feat5": "24/7 dedizierter Support", + "pricing.plans.enterprise.feat6": "White-Label", + "pricing.plans.enterprise.feat7": "Unbegrenzte Teams", + "pricing.plans.enterprise.feat8": "Maßgeschneiderte Integrationen", + "pricing.card.onRequest": "Auf Anfrage", + "pricing.card.free": "Kostenlos", + "pricing.card.perMonth": "/Monat", + "pricing.card.billedYearly": "{price} € / Jahr abgerechnet", + "pricing.card.documents": "Dokumente", + "pricing.card.pagesMax": "Max. Seiten", + "pricing.card.aiTranslation": "KI-Übersetzung", + "pricing.card.unlimited": "Unbegrenzt", + "pricing.card.perMonthStat": "/ Monat", + "pricing.card.perDoc": "S. / Dok.", + "pricing.card.aiEssential": "Basis", + "pricing.card.aiEssentialPremium": "Basis + Premium", + "pricing.card.aiCustom": "Maßgeschneidert", + "pricing.card.myPlan": "Mein Plan", + "pricing.card.managePlan": "Plan verwalten", + "pricing.card.startFree": "Kostenlos starten", + "pricing.card.contactUs": "Kontaktieren Sie uns", + "pricing.card.choosePlan": "Diesen Plan wählen", + "pricing.card.processing": "Wird verarbeitet…", + "pricing.comparison.title": "Detaillierter Vergleich", + "pricing.comparison.subtitle": "Alles, was in jedem Plan enthalten ist", + "pricing.comparison.feature": "Funktion", + "pricing.comparison.docsPerMonth": "Dokumente / Monat", + "pricing.comparison.pagesMaxPerDoc": "Max. Seiten / Dokument", + "pricing.comparison.maxFileSize": "Max. Dateigröße", + "pricing.comparison.googleTranslation": "Google Übersetzer", + "pricing.comparison.deepl": "DeepL", + "pricing.comparison.aiEssential": "KI-Basisübersetzung", + "pricing.comparison.aiPremium": "KI-Premiumübersetzung", + "pricing.comparison.apiAccess": "API-Zugang", + "pricing.comparison.priorityProcessing": "Prioritätsverarbeitung", + "pricing.comparison.support": "Support", + "pricing.comparison.support.community": "Community", + "pricing.comparison.support.email": "E-Mail", + "pricing.comparison.support.priority": "Priorität", + "pricing.comparison.support.dedicated": "Dediziert", + "pricing.comparison.mb": "MB", + "pricing.credits.title": "Zusätzliche Guthaben", + "pricing.credits.subtitle": "Mehr benötigt? Guthaben einzeln kaufen, ohne Abo.", + "pricing.credits.perPage": "1 Guthaben = 1 übersetzte Seite.", + "pricing.credits.bestValue": "Bestes Preis-Leistungs-Verhältnis", + "pricing.credits.unit": "Guthaben", + "pricing.credits.centsPerCredit": "ct / Guthaben", + "pricing.credits.buy": "Kaufen", + "pricing.trust.encryption.title": "Ende-zu-Ende-Verschlüsselung", + "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 im Ruhezustand", + "pricing.trust.languages.title": "130+ Sprachen", + "pricing.trust.languages.sub": "Einschließlich Arabisch, Persisch, Hebräisch (RTL)", + "pricing.trust.parallel.title": "Parallele Verarbeitung", + "pricing.trust.parallel.sub": "Ultraschnelle Multi-Thread-KI", + "pricing.trust.availability.title": "24/7 verfügbar", + "pricing.trust.availability.sub": "99,9 % garantierte Verfügbarkeit", + "pricing.aiModels.title": "Unsere KI-Modelle — März 2026", + "pricing.aiModels.essential.title": "KI-Basisübersetzung", + "pricing.aiModels.essential.plan": "Pro-Plan", + "pricing.aiModels.essential.descPrefix": "Basierend auf", + "pricing.aiModels.essential.descSuffix": "— dem kosteneffizientesten KI-Modell 2026. Qualität vergleichbar mit Frontier-Modellen zu einem Bruchteil der Kosten.", + "pricing.aiModels.essential.modelName": "unser Essentielles KI-Modell", + "pricing.aiModels.essential.context": "163K Token Kontext", + "pricing.aiModels.essential.value": "Hervorragendes Preis-Leistungs-Verhältnis", + "pricing.aiModels.premium.title": "KI-Premiumübersetzung", + "pricing.aiModels.premium.plan": "Business-Plan", + "pricing.aiModels.premium.descPrefix": "Basierend auf", + "pricing.aiModels.premium.descSuffix": "von Anthropic — präzise bei juristischen, medizinischen und komplexen technischen Dokumenten.", + "pricing.aiModels.premium.context": "200K Token Kontext", + "pricing.aiModels.premium.precision": "Höchste Genauigkeit", + "pricing.faq.title": "Häufig gestellte Fragen", + "pricing.faq.q1": "Kann ich jederzeit den Plan wechseln?", + "pricing.faq.a1": "Ja. Ein Upgrade erfolgt sofort und anteilig. Ein Downgrade wird am Ende des aktuellen Zeitraums wirksam.", + "pricing.faq.q2": "Was ist die «KI-Basisübersetzung»?", + "pricing.faq.a2": "Unser KI-Motor versteht den Kontext Ihrer Dokumente, erhält das Layout und verarbeitet Fachbegriffe deutlich besser als klassische Übersetzungen.", + "pricing.faq.q3": "Was ist der Unterschied zwischen Basis- und Premium-KI?", + "pricing.faq.a3": "Die Basis-KI nutzt ein optimiertes Modell (hervorragendes Preis-Leistungs-Verhältnis). Die Premium-KI verwendet Claude 3.5 Haiku von Anthropic und ist genauer bei juristischen, medizinischen und komplexen technischen Dokumenten.", + "pricing.faq.q4": "Werden meine Dokumente nach der Übersetzung gespeichert?", + "pricing.faq.a4": "Übersetzte Dateien sind je nach Plan verfügbar (30 Tage Starter, 90 Tage Pro, 1 Jahr Business). Sie sind im Ruhezustand und bei der Übertragung verschlüsselt.", + "pricing.faq.q5": "Was passiert, wenn ich mein monatliches Kontingent überschreite?", + "pricing.faq.a5": "Sie können einzelne Guthaben kaufen oder Ihr Abo upgraden. Sie werden bei 80 % Nutzung benachrichtigt.", + "pricing.faq.q6": "Gibt es eine kostenlose Testversion für kostenpflichtige Pläne?", + "pricing.faq.a6": "Der Kostenlos-Plan ist dauerhaft und ohne Kreditkarte. Für Pro und Business kontaktieren Sie uns für eine 14-tägige Testphase.", + "pricing.faq.q7": "Welche Dateiformate werden unterstützt?", + "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx) und bald PDF. Alle Pläne unterstützen dieselben Formate.", + "pricing.cta.title": "Bereit loszulegen?", + "pricing.cta.subtitle": "Starten Sie kostenlos, ohne Kreditkarte. Upgraden Sie, wenn Sie möchten.", + "pricing.cta.createAccount": "Kostenloses Konto erstellen", + "pricing.cta.login": "Anmelden", + "pricing.toast.demo": "Demo-Modus — Stripe ist noch nicht konfiguriert. In der Produktion würden Sie zur Zahlung weitergeleitet, um den Plan {planId} zu aktivieren.", + "pricing.toast.networkError": "Netzwerkfehler. Bitte versuchen Sie es erneut.", + "pricing.toast.paymentError": "Fehler beim Erstellen der Zahlung.", + "pricing.dashboard": "Dashboard", + "pricing.okSymbol": "✓", + "pricing.errSymbol": "✕" +} diff --git a/frontend/src/lib/i18n/messages/de/profile.json b/frontend/src/lib/i18n/messages/de/profile.json new file mode 100644 index 0000000..6baacf4 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/profile.json @@ -0,0 +1,58 @@ +{ + "profile.header.title": "Mein Profil", + "profile.header.subtitle": "Verwalten Sie Ihr Konto und Ihre Einstellungen.", + "profile.tabs.account": "Konto", + "profile.tabs.subscription": "Abonnement", + "profile.tabs.preferences": "Einstellungen", + "profile.account.user": "Benutzer", + "profile.account.memberSince": "Mitglied seit", + "profile.plan.label": "Plan", + "profile.plan.free": "Kostenlos", + "profile.plan.starter": "Starter", + "profile.plan.pro": "Pro", + "profile.plan.business": "Business", + "profile.plan.enterprise": "Enterprise", + "profile.plan.pricePerMonth": "{price} €/Monat", + "profile.subscription.canceling": "Kündigung läuft", + "profile.subscription.active": "Aktiv", + "profile.subscription.unknown": "Unbekannt", + "profile.subscription.accessUntil": "Zugang bis", + "profile.subscription.renewalOn": "Verlängerung am", + "profile.subscription.upgradePlan": "Auf einen kostenpflichtigen Plan upgraden", + "profile.subscription.changePlan": "Plan ändern", + "profile.subscription.manageBilling": "Abrechnung verwalten", + "profile.subscription.billingUnavailable": "Abrechnungsportal nicht verfügbar.", + "profile.subscription.billingError": "Fehler beim Zugriff auf das Abrechnungsportal.", + "profile.subscription.cancelSuccess": "Abonnement gekündigt. Sie behalten den Zugang bis zum Ende des Zeitraums.", + "profile.subscription.cancelError": "Fehler bei der Kündigung.", + "profile.subscription.networkError": "Netzwerkfehler.", + "profile.usage.title": "Nutzung diesen Monat", + "profile.usage.resetOn": "Zurücksetzung am", + "profile.usage.documents": "Dokumente", + "profile.usage.pages": "Seiten", + "profile.usage.extraCredits": "zusätzliches Guthaben", + "profile.usage.extraCreditsPlural": "zusätzliches Guthaben", + "profile.usage.quotaReached": "Kontingent erreicht", + "profile.usage.quotaReachedDesc": "Upgraden Sie auf einen höheren Plan, um fortzufahren.", + "profile.usage.unlockMore": "Schalten Sie mit einem kostenpflichtigen Plan mehr Übersetzungen frei.", + "profile.usage.viewPlans": "Pläne ansehen", + "profile.usage.includedInPlan": "In Ihrem Plan enthalten", + "profile.danger.title": "Gefahrenzone", + "profile.danger.description": "Die Kündigung wird am Ende Ihres aktuellen Zeitraums wirksam. Sie behalten den Zugang bis zu diesem Datum.", + "profile.danger.confirm": "Sind Sie sicher? Diese Aktion kann nicht rückgängig gemacht werden.", + "profile.danger.confirmCancel": "Kündigung bestätigen", + "profile.danger.cancelSubscription": "Mein Abonnement kündigen", + "profile.danger.keep": "Nein, behalten", + "profile.prefs.interfaceLang": "Sprache der Benutzeroberfläche", + "profile.prefs.interfaceLangDesc": "Die Sprache wird automatisch anhand Ihres Browsers erkannt. Sie können sie manuell ändern.", + "profile.prefs.defaultTargetLang": "Standard-Zielsprache", + "profile.prefs.selectLanguage": "Sprache auswählen", + "profile.prefs.defaultTargetLangDesc": "Diese Sprache wird für Ihre Übersetzungen vorausgewählt.", + "profile.prefs.save": "Speichern", + "profile.prefs.theme": "Design", + "profile.prefs.themeDesc": "Wählen Sie das Erscheinungsbild der Benutzeroberfläche", + "profile.prefs.cache": "Cache", + "profile.prefs.cacheDesc": "Das Löschen des lokalen Caches kann einige Anzeigeprobleme beheben.", + "profile.prefs.clearing": "Wird gelöscht...", + "profile.prefs.clearCache": "Cache löschen" +} diff --git a/frontend/src/lib/i18n/messages/de/providerSelector.json b/frontend/src/lib/i18n/messages/de/providerSelector.json new file mode 100644 index 0000000..6bf8d2c --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/providerSelector.json @@ -0,0 +1,7 @@ +{ + "providerSelector.noClassic": "Kein Standard-Übersetzer verfügbar.", + "providerSelector.noLlm": "Kein KI-Modell konfiguriert.", + "providerSelector.costOne": "Kosten: 1 Guthaben pro Seite", + "providerSelector.costFive": "Kosten: 5 Guthaben pro Seite (Premium-Faktor)", + "providerSelector.unlockContextual": "Premium-Kontextübersetzung für Ihre gesamten Dokumente freischalten." +} diff --git a/frontend/src/lib/i18n/messages/de/providerTheme.json b/frontend/src/lib/i18n/messages/de/providerTheme.json new file mode 100644 index 0000000..5f299d4 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/providerTheme.json @@ -0,0 +1,29 @@ +{ + "providerTheme.deepseek.badge": "Essenziell", + "providerTheme.deepseek.subBadge": "Technisch & Sparsam", + "providerTheme.deepseek.desc": "Ultrapräzise und wirtschaftliche Übersetzung, ideal für technische Dokumente und Code.", + "providerTheme.openai.badge": "Premium", + "providerTheme.openai.subBadge": "Hohe Treue", + "providerTheme.openai.desc": "Der globale KI-Standard. Maximale Textkonsistenz und strenge Stileinhaltung.", + "providerTheme.minimax.badge": "Erweitert", + "providerTheme.minimax.subBadge": "Leistung", + "providerTheme.minimax.desc": "Unglaubliche Ausführungsgeschwindigkeit und ausgezeichnetes Verständnis komplexer Strukturen.", + "providerTheme.openrouter.badge": "Express", + "providerTheme.openrouter.subBadge": "Multi-Modell", + "providerTheme.openrouter.desc": "Einheitlicher Zugriff auf die besten Open-Source-Modelle, optimiert für Übersetzung.", + "providerTheme.openrouter_premium.badge": "Ultra", + "providerTheme.openrouter_premium.subBadge": "Maximaler Kontext", + "providerTheme.openrouter_premium.desc": "Unterstützt durch modernste Modelle (GPT-4o, Claude Sonnet 4.6) für lange Dokumente.", + "providerTheme.zai.badge": "Spezialisiert", + "providerTheme.zai.subBadge": "Finanzen & Recht", + "providerTheme.zai.desc": "Modell feinabgestimmt auf anspruchsvolle Geschäftsterminologien (Recht, Finanzen).", + "providerTheme.default.badge": "Modern", + "providerTheme.default.subBadge": "KI-Argumentation", + "providerTheme.default.desc": "Großsprachmodell-Übersetzung (LLM) mit fortgeschrittener semantischer Analyse.", + "providerTheme.classic.google.label": "Google Übersetzer", + "providerTheme.classic.google.desc": "Ultraschnelle Übersetzung für über 130 Sprachen. Empfohlen für allgemeine Abläufe.", + "providerTheme.classic.deepl.label": "DeepL Pro", + "providerTheme.classic.deepl.desc": "Hochpräzise Übersetzung, bekannt für Flüssigkeit und natürliche Formulierungen.", + "providerTheme.classic.google_cloud.label": "Google Cloud API", + "providerTheme.classic.google_cloud.desc": "Professionelle Cloud-Engine, optimiert für die Verarbeitung großer Dokumentenmengen." +} diff --git a/frontend/src/lib/i18n/messages/de/register.json b/frontend/src/lib/i18n/messages/de/register.json new file mode 100644 index 0000000..7295d87 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/register.json @@ -0,0 +1,29 @@ +{ + "register.title": "Konto erstellen", + "register.subtitle": "Kostenlos mit dem Übersetzen beginnen", + "register.error.failed": "Registrierung fehlgeschlagen", + "register.name.label": "Name", + "register.name.placeholder": "Ihr Name", + "register.name.error": "Der Name muss mindestens 2 Zeichen lang sein", + "register.email.label": "E-Mail-Adresse", + "register.email.placeholder": "sie@beispiel.de", + "register.email.error": "Ungültige E-Mail-Adresse", + "register.password.label": "Passwort", + "register.password.error": "Das Passwort muss mindestens 8 Zeichen haben, mit Großbuchstabe, Kleinbuchstabe und Ziffer", + "register.password.show": "Passwort anzeigen", + "register.password.hide": "Passwort verbergen", + "register.password.strengthLabel": "Stärke:", + "register.password.strength.weak": "Schwach", + "register.password.strength.medium": "Mittel", + "register.password.strength.strong": "Stark", + "register.confirmPassword.label": "Passwort bestätigen", + "register.confirmPassword.error": "Passwörter stimmen nicht überein", + "register.confirmPassword.show": "Anzeigen", + "register.confirmPassword.hide": "Verbergen", + "register.submit.creating": "Konto wird erstellt...", + "register.submit.create": "Mein Konto erstellen", + "register.hasAccount": "Bereits ein Konto?", + "register.login": "Anmelden", + "register.terms.prefix": "Mit der Kontoerstellung akzeptieren Sie unsere", + "register.terms.link": "Nutzungsbedingungen" +} diff --git a/frontend/src/lib/i18n/messages/de/resetPassword.json b/frontend/src/lib/i18n/messages/de/resetPassword.json new file mode 100644 index 0000000..680714f --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/resetPassword.json @@ -0,0 +1,22 @@ +{ + "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", + "resetPassword.passwordMismatch": "Passwords do not match", + "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", + "resetPassword.error": "An error occurred", + "resetPassword.invalidLink": "Invalid link", + "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", + "resetPassword.requestNewLink": "Request new link", + "resetPassword.successTitle": "Password reset", + "resetPassword.newPasswordTitle": "New password", + "resetPassword.successSubtitle": "You will be redirected to login", + "resetPassword.subtitle": "Set your new password", + "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", + "resetPassword.newPassword": "New password", + "resetPassword.showPassword": "Show password", + "resetPassword.hidePassword": "Hide password", + "resetPassword.confirmPassword": "Confirm password", + "resetPassword.resetting": "Resetting...", + "resetPassword.resetPassword": "Reset password", + "resetPassword.backToLogin": "Back to login", + "resetPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/de/services.json b/frontend/src/lib/i18n/messages/de/services.json new file mode 100644 index 0000000..e0f4f2d --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/services.json @@ -0,0 +1,14 @@ +{ + "services.title": "Übersetzungsanbieter", + "services.subtitle": "Anbieter werden vom Administrator konfiguriert. Sie können sehen, welche derzeit für Ihr Konto verfügbar sind.", + "services.loading": "Anbieter werden geladen...", + "services.noProviders": "Derzeit sind keine Anbieter konfiguriert. Wenden Sie sich an Ihren Administrator.", + "services.classic": "Klassische Übersetzung", + "services.llmPro": "LLM · Kontextbezogen (Pro)", + "services.available": "Verfügbar", + "services.model": "Modell", + "services.adminOnly.title": "Anbieterkonfiguration ist nur für Administratoren", + "services.adminOnly.desc": "API-Schlüssel, Modellauswahl und Anbieteraktivierung werden ausschließlich vom Administrator im Admin-Panel verwaltet. Sie müssen niemals einen API-Schlüssel eingeben.", + "services.fallback.google.label": "Google Übersetzer", + "services.fallback.google.desc": "Schnelle Übersetzung, über 130 Sprachen" +} diff --git a/frontend/src/lib/i18n/messages/de/settings.json b/frontend/src/lib/i18n/messages/de/settings.json new file mode 100644 index 0000000..88c21be --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/settings.json @@ -0,0 +1,20 @@ +{ + "settings.title": "Einstellungen", + "settings.subtitle": "Allgemeine Anwendungskonfiguration", + "settings.formats.title": "Unterstützte Formate", + "settings.formats.subtitle": "Dokumenttypen, die Sie übersetzen können", + "settings.formats.formulas": "Formeln", + "settings.formats.styles": "Stile", + "settings.formats.images": "Bilder", + "settings.formats.headers": "Kopfzeilen", + "settings.formats.tables": "Tabellen", + "settings.formats.slides": "Folien", + "settings.formats.notes": "Notizen", + "settings.cache.title": "Cache", + "settings.cache.desc": "Das Löschen des lokalen Caches kann einige Anzeigeprobleme beheben.", + "settings.cache.clearing": "Wird gelöscht...", + "settings.cache.clear": "Cache löschen", + "settings.formats.excel.name": "Excel", + "settings.formats.word.name": "Word", + "settings.formats.powerpoint.name": "PowerPoint" +} diff --git a/frontend/src/lib/i18n/messages/de/translate.json b/frontend/src/lib/i18n/messages/de/translate.json new file mode 100644 index 0000000..2455d8f --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/translate.json @@ -0,0 +1,92 @@ +{ + "translate.mode.label": "Mode de traduction", + "translate.mode.classic": "Classique", + "translate.mode.classicDesc": "Rapide", + "translate.mode.proLlm": "Pro LLM", + "translate.mode.proLlmDesc": "Contextuel", + "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", + "translate.mode.upgradeLink": "Passer à Pro", + "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", + "translate.glossary.title": "Glossar", + "translate.glossary.select": "Glossar auswählen", + "translate.glossary.none": "Keins", + "translate.glossary.terms": "Begriffe", + "translate.glossary.proOnly": "Upgraden Sie auf Pro für Glossare", + "translate.glossary.myGlossaries": "Meine Glossare", + "translate.glossary.fromTemplate": "Aus Vorlage erstellen", + "translate.glossary.noGlossaryForPair": "Kein Glossar für", + "translate.glossary.noGlossaries": "Keine Glossare", + "translate.glossary.loading": "Laden...", + "translate.glossary.classicMode": "Neutraler Motor ohne Glossar (nur KI)", + "translate.glossary.selectPlaceholder": "Glossar auswählen...", + "translate.glossary.multilingual": "MEHRSPRACHIG", + "translate.glossary.noGlossaryAvailable": "Kein Glossar verfügbar", + "translate.glossary.filterByLang": "Nach Sprache filtern", + "translate.glossary.active": "Aktiv", + "translate.glossary.inactive": "Inaktiv", + "translate.glossary.availableTemplates": "Verfügbare Vorlagen", + "translate.glossary.importing": "Importiere...", + "translate.glossary.imported": "(Importiert)", + "translate.glossary.noGlossaryForSource": "Kein Glossar oder Vorlage für Ausgangssprache", + "translate.glossary.createGlossary": "Glossar erstellen", + "translate.glossary.showAll": "Alle Glossare anzeigen", + "translate.glossary.activePreview": "Vorschau aktiver Zuordnungen:", + "translate.glossary.total": "gesamt", + "translate.glossary.moreTerms": "weitere Begriffe", + "translate.glossary.noTerms": "Keine Begriffe in diesem Glossar.", + "translate.glossary.sourceTerm": "Quellbegriff", + "translate.glossary.translation": "Übersetzung", + "translate.glossary.addTerm": "Begriff hinzufügen", + "translate.glossary.disabledMode": "Neutraler Motor ohne angewandtes Glossar", + "translate.glossary.addTermError": "Fehler beim Hinzufügen des Begriffs", + "translate.glossary.networkError": "Netzwerkfehler", + "translate.glossary.importFailed": "Import fehlgeschlagen ({status})", + "translate.glossary.helpText": "Das Glossar erzwingt die präzise Übersetzung von Begriffen. Wählen Sie ein Glossar, dessen Ausgangssprache der Originalsprache Ihres Dokuments entspricht.", + "translate.glossary.sourceWarning": "Achtung: Dieses Glossar verwendet die Ausgangssprache", + "translate.glossary.sourceWarningBut": "aber Ihr Dokument ist konfiguriert auf", + "translate.glossary.targetWarning": "Ziel-Inkompatibilität: Dieses Glossar ist für die Übersetzung in", + "translate.glossary.targetWarningBut": "aber Ihr Dokument zielt auf", + "translate.glossary.targetWarningEnd": "Die Begriffe sind möglicherweise nicht relevant.", + "translate.header.processing": "Verarbeitung läuft", + "translate.header.aiActive": "KI-Analyse aktiv", + "translate.header.aiActiveDesc": "Ihr Layout wird von unserer kontextuellen Engine beibehalten.", + "translate.header.completed": "Abgeschlossen", + "translate.header.completedTitle": "Übersetzung abgeschlossen", + "translate.header.proSpace": "Pro-Bereich", + "translate.header.translateDoc": "Dokument übersetzen", + "translate.header.translateDocDesc": "Behalten Sie das Originallayout mit unserer Ultra-High-Fidelity-Übersetzungs-Engine.", + "translate.upload.nativeFormat": "Natives Format", + "translate.fileType.word": "Word (.docx)", + "translate.fileType.excel": "Excel (.xlsx)", + "translate.fileType.slides": "Folien (.pptx)", + "translate.fileType.pdf": "PDF (.pdf)", + "translate.startTranslation": "Übersetzung starten", + "translate.submit": "Wird gesendet…", + "translate.chooseTargetLang": "Bitte wählen Sie eine Zielsprache", + "translate.pleaseLoadFile": "Bitte laden Sie zuerst eine Datei hoch", + "translate.contextEngineActive": "Kontextuelle Engine aktiv", + "translate.phase1": "Phase 1: Initialisierung", + "translate.phase2": "Phase 2: Kontextuelle Rekonstruktion", + "translate.stat.segments": "Segmente", + "translate.stat.precision": "Genauigkeit", + "translate.stat.speedLabel": "Geschwindigkeit", + "translate.stat.turbo": "Turbo", + "translate.stat.time": "Zeit", + "translate.complete.masterQuality": "✓ Meister-Qualität", + "translate.download": "Herunterladen", + "translate.newTranslation": "+ Neue Übersetzung", + "translate.failedTitle": "Übersetzungsfehler", + "translate.retry": "Erneut versuchen", + "translate.uploadAnother": "Andere Datei hochladen", + "translate.monitor": "KI-Monitor", + "translate.summary": "Zusammenfassung", + "translate.cancelProcess": "⟳ Prozess abbrechen", + "translate.layoutIntegrity": "Layout-Integrität", + "translate.secureHundred": "100% SICHER", + "translate.okHundred": "100% OK", + "translate.preserveLayout": "Layout beibehalten", + "translate.preserveLayoutDesc": "Layout beibehalten", + "translate.textOnly": "Nur Text", + "translate.textOnlyDesc": "Schnelle Übersetzung nur des Textes", + "translate.unavailableStandard": "Im Standardmodus nicht verfügbar (nur KI)" +} diff --git a/frontend/src/lib/i18n/messages/de/translateComplete.json b/frontend/src/lib/i18n/messages/de/translateComplete.json new file mode 100644 index 0000000..18f8e19 --- /dev/null +++ b/frontend/src/lib/i18n/messages/de/translateComplete.json @@ -0,0 +1,6 @@ +{ + "translateComplete.highQuality": "Hohe Qualität", + "translateComplete.segments": "Segmente", + "translateComplete.characters": "Zeichen", + "translateComplete.confidence": "Vertrauen" +} diff --git a/frontend/src/lib/i18n/messages/en/admin.json b/frontend/src/lib/i18n/messages/en/admin.json new file mode 100644 index 0000000..a95dbd6 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/admin.json @@ -0,0 +1,48 @@ +{ + "admin.login.title": "Administration", + "admin.login.required": "Login required", + "admin.login.password": "Admin password", + "admin.login.connecting": "Connecting...", + "admin.login.access": "Access admin panel", + "admin.login.restricted": "Restricted to administrators", + "admin.layout.checking": "Verifying authentication...", + "admin.dashboard.title": "Admin Dashboard", + "admin.dashboard.subtitle": "Administrator control panel", + "admin.dashboard.refresh": "Refresh", + "admin.dashboard.refreshTooltip": "Refresh dashboard data", + "admin.dashboard.config": "System Configuration", + "admin.dashboard.maxFileSize": "Max file size:", + "admin.dashboard.translationService": "Translation service:", + "admin.dashboard.formats": "Formats:", + "admin.nav.dashboard": "Dashboard", + "admin.nav.users": "Users", + "admin.nav.pricing": "Pricing & Stripe", + "admin.nav.providers": "Providers", + "admin.nav.system": "System", + "admin.nav.logs": "Logs", + "admin.users.title": "User Management", + "admin.users.subtitle": "View and manage user accounts", + "admin.users.planUpdated": "Plan updated", + "admin.users.planChanged": "The plan has been changed to \\\"{plan}\\\" successfully.", + "admin.users.unknownError": "Unknown error", + "admin.users.error": "Error", + "admin.users.planUpdateError": "Unable to update plan: {message}", + "admin.users.noKeys": "No keys", + "admin.users.noKeysDesc": "This user has no active API keys.", + "admin.users.keysRevoked": "Keys revoked", + "admin.users.keysRevokedDesc": "{count} API key(s) revoked successfully.", + "admin.users.revokeError": "Unable to revoke keys: {message}", + "admin.users.retry": "Retry", + "admin.system.title": "System", + "admin.system.subtitle": "Monitor system status and manage resources", + "admin.system.quotas": "Translation quotas", + "admin.system.resetQuotas": "Reset monthly quotas", + "admin.system.resetting": "Resetting...", + "admin.system.reset": "Reset", + "admin.system.allOperational": "All Systems Operational", + "admin.system.issuesDetected": "System Issues Detected", + "admin.system.waitingData": "Waiting for data...", + "admin.system.purging": "Purging...", + "admin.system.clean": "Clean", + "admin.system.purge": "Purge" +} diff --git a/frontend/src/lib/i18n/messages/en/apiKeys.json b/frontend/src/lib/i18n/messages/en/apiKeys.json new file mode 100644 index 0000000..863199c --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/apiKeys.json @@ -0,0 +1,72 @@ +{ + "apiKeys.webhook.title": "Webhook Integration", + "apiKeys.webhook.descriptionBefore": "Pass a ", + "apiKeys.webhook.descriptionAfter": " parameter to receive a POST request when your translation is complete.", + "apiKeys.webhook.codeParam": "webhook_url", + "apiKeys.title": "API Keys", + "apiKeys.subtitle": "Manage your API keys for programmatic access to the translation API.", + "apiKeys.loading": "Loading...", + "apiKeys.sectionTitle": "API & Automation", + "apiKeys.sectionDesc": "Generate and manage your API keys for automation workflows", + "apiKeys.keysUsed": "{total} of {max} keys used", + "apiKeys.maxReached": "Maximum keys reached. Revoke a key to generate a new one.", + "apiKeys.canGenerate": "You can generate {count} more key", + "apiKeys.canGeneratePlural": "You can generate {count} more keys", + "apiKeys.generateNew": "Generate New Key", + "apiKeys.keyRevoked": "Key revoked", + "apiKeys.keyRevokedDesc": "The API key has been revoked successfully.", + "apiKeys.keyNotFound": "Key Not Found", + "apiKeys.keyNotFoundDesc": "The API key no longer exists. It may have already been revoked.", + "apiKeys.error": "Error", + "apiKeys.revokeError": "Failed to revoke the API key. Please try again.", + "apiKeys.limitReached": "Limit Reached", + "apiKeys.limitReachedDesc": "You have reached the maximum of 10 API keys. Revoke an existing key to generate a new one.", + "apiKeys.proRequired": "Pro Feature Required", + "apiKeys.proRequiredDesc": "API keys are a Pro feature. Please upgrade your account.", + "apiKeys.generateError": "Failed to generate API key. Please try again.", + "apiKeys.upgrade.title": "API Keys", + "apiKeys.upgrade.subtitle": "Automate your translations with API access", + "apiKeys.upgrade.feat1": "Generate unlimited API keys", + "apiKeys.upgrade.feat2": "Automate document translation", + "apiKeys.upgrade.feat3": "Webhook notifications", + "apiKeys.upgrade.feat4": "LLM translation modes", + "apiKeys.upgrade.proFeature": "API Keys are a {pro} feature. Upgrade to unlock API automation.", + "apiKeys.upgrade.pro": "Pro", + "apiKeys.upgrade.cta": "Upgrade to Pro", + "apiKeys.dialog.maxTitle": "Maximum Keys Reached", + "apiKeys.dialog.maxDesc": "You have reached the maximum of 10 API keys. Please revoke an existing key before generating a new one.", + "apiKeys.dialog.close": "Close", + "apiKeys.dialog.generated": "API Key Generated!", + "apiKeys.dialog.generatedDesc": "Your new API key has been created. Copy it now - it won't be shown again.", + "apiKeys.dialog.important": "Important:", + "apiKeys.dialog.importantDesc": "This is the only time you'll see this key. Store it securely.", + "apiKeys.dialog.apiKey": "API Key", + "apiKeys.dialog.name": "Name:", + "apiKeys.dialog.done": "Done", + "apiKeys.dialog.copied": "I've copied the key", + "apiKeys.dialog.generateTitle": "Generate New API Key", + "apiKeys.dialog.generateDesc": "Create a new API key for programmatic access to the translation API.", + "apiKeys.dialog.keyName": "Key Name (optional)", + "apiKeys.dialog.keyNamePlaceholder": "e.g., Production, Staging", + "apiKeys.dialog.keyNameHint": "A descriptive name to help you identify this key later.", + "apiKeys.dialog.nameTooLong": "Name must be {max} characters or less", + "apiKeys.dialog.nameInvalid": "Name can only contain letters, numbers, spaces, hyphens, and underscores", + "apiKeys.dialog.cancel": "Cancel", + "apiKeys.dialog.generating": "Generating...", + "apiKeys.dialog.generate": "Generate Key", + "apiKeys.table.name": "Name", + "apiKeys.table.prefix": "Prefix", + "apiKeys.table.created": "Created", + "apiKeys.table.lastUsed": "Last used", + "apiKeys.table.never": "Never", + "apiKeys.table.actions": "Actions", + "apiKeys.table.revoke": "Revoke", + "apiKeys.table.copyPrefix": "Copy key prefix", + "apiKeys.table.revokeKey": "Revoke key", + "apiKeys.revokeDialog.title": "Revoke API Key", + "apiKeys.revokeDialog.desc": "Are you sure you want to revoke the key \\\"{name}\\\"? This action cannot be undone.", + "apiKeys.revokeDialog.confirm": "Yes, revoke", + "apiKeys.revokeDialog.cancel": "Cancel", + "apiKeys.noKeysGenerated": "No keys generated", + "apiKeys.copied": "Copied!" +} diff --git a/frontend/src/lib/i18n/messages/en/auth.json b/frontend/src/lib/i18n/messages/en/auth.json new file mode 100644 index 0000000..b300370 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/auth.json @@ -0,0 +1,3 @@ +{ + "auth.brandName": "Wordly" +} diff --git a/frontend/src/lib/i18n/messages/en/checkout.json b/frontend/src/lib/i18n/messages/en/checkout.json new file mode 100644 index 0000000..d4ae781 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/checkout.json @@ -0,0 +1,12 @@ +{ + "checkout.activating": "Activating…", + "checkout.activatingDesc": "We are updating your subscription, please wait.", + "checkout.paymentConfirmed": "Payment confirmed!", + "checkout.subscriptionActivated": "Subscription activated!", + "checkout.planActivated": "{plan} plan activated!", + "checkout.redirectingToProfile": "Redirecting to your profile…", + "checkout.paymentReceived": "Payment received", + "checkout.redirecting": "Redirecting…", + "checkout.syncError": "Sync error", + "checkout.networkError": "Network error. Your payment is confirmed — please reload your profile." +} diff --git a/frontend/src/lib/i18n/messages/en/common.json b/frontend/src/lib/i18n/messages/en/common.json new file mode 100644 index 0000000..a102dd3 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/common.json @@ -0,0 +1,4 @@ +{ + "common.loading": "Loading...", + "common.backToHome": "Back to home" +} diff --git a/frontend/src/lib/i18n/messages/en/context.json b/frontend/src/lib/i18n/messages/en/context.json new file mode 100644 index 0000000..2d396f5 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/context.json @@ -0,0 +1,25 @@ +{ + "context.proTitle": "Pro Feature", + "context.proDesc": "Context and professional glossaries are available with Pro, Business and Enterprise plans. They provide more accurate translations through instructions and vocabulary specific to your domain.", + "context.viewPlans": "View plans", + "context.title": "Context & Glossary", + "context.subtitle": "Improve translation quality with instructions and vocabulary specific to your domain.", + "context.presets.title": "Professional glossaries", + "context.presets.desc": "Load a complete glossary with instructions and specialized terminology", + "context.instructions.title": "Context instructions", + "context.instructions.desc": "Instructions the AI will follow during translation", + "context.instructions.placeholder": "E.g.: You translate HVAC technical documents. Use precise engineering terminology...", + "context.glossary.title": "Technical glossary", + "context.glossary.desc": "Format: source=target (one per line). Glossaries loaded via preset are editable.", + "context.glossary.terms": "terms in the glossary", + "context.clearAll": "Clear all", + "context.saving": "Saving...", + "context.save": "Save", + "context.presets.createGlossary": "Create glossary", + "context.presets.created": "Glossary created", + "context.presets.createdDesc": "The glossary \\\"{name}\\\" has been created with {count} terms.", + "context.presets.hint": "Click a preset to create a glossary with domain-specific terms. Manage your glossaries in the Glossaries section.", + "context.glossary.manage": "Manage glossaries", + "context.saved": "Saved", + "context.savedDesc": "Your context instructions have been saved." +} diff --git a/frontend/src/lib/i18n/messages/en/cookieConsent.json b/frontend/src/lib/i18n/messages/en/cookieConsent.json new file mode 100644 index 0000000..a0eb822 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/cookieConsent.json @@ -0,0 +1,7 @@ +{ + "cookieConsent.title": "Cookies on Wordly", + "cookieConsent.description": "We use essential cookies so the app works (session, security, language). With your permission, we also use optional cookies to measure traffic and improve the product.", + "cookieConsent.acceptAll": "Accept all", + "cookieConsent.essentialOnly": "Essential only", + "cookieConsent.learnMore": "Learn more" +} diff --git a/frontend/src/lib/i18n/messages/en/dashboard.json b/frontend/src/lib/i18n/messages/en/dashboard.json new file mode 100644 index 0000000..2542af0 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/dashboard.json @@ -0,0 +1,115 @@ +{ + "dashboard.nav.translate": "Translate", + "dashboard.nav.profile": "My Profile", + "dashboard.nav.settings": "Settings", + "dashboard.nav.context": "Context", + "dashboard.nav.services": "Services", + "dashboard.nav.apiKeys": "API Keys", + "dashboard.nav.glossaries": "Glossaries & Context", + "dashboard.header.title": "Dashboard", + "dashboard.header.subtitle": "Manage your translations", + "dashboard.header.toggleMenu": "Menu", + "dashboard.header.profileTitle": "My profile", + "dashboard.sidebar.theme": "Theme", + "dashboard.sidebar.signOut": "Sign Out", + "dashboard.sidebar.backHome": "Back to Home", + "dashboard.sidebar.upgradeToPro": "Upgrade to Pro →", + "dashboard.translate.pageTitle": "Translate a document", + "dashboard.translate.pageSubtitle": "Import a file and choose the target language", + "dashboard.translate.errorNotificationTitle": "Error", + "dashboard.translate.dropzone.uploadAria": "File drop zone", + "dashboard.translate.dropzone.title": "Drag & drop your file here", + "dashboard.translate.dropzone.subtitle": "or click to select (DOCX, XLSX, PPTX, PDF)", + "dashboard.translate.dropzone.replaceFile": "Replace file", + "dashboard.translate.language.source": "Source language", + "dashboard.translate.language.target": "Target language", + "dashboard.translate.language.loading": "Loading languages…", + "dashboard.translate.language.autoDetect": "Auto-detect", + "dashboard.translate.language.selectPlaceholder": "Select…", + "dashboard.translate.language.loadErrorPrefix": "Failed to load languages", + "dashboard.translate.provider.loading": "Loading providers…", + "dashboard.translate.provider.noneConfigured": "No providers configured", + "dashboard.translate.provider.modelTitle": "Model", + "dashboard.translate.provider.sectionTitle": "Provider", + "dashboard.translate.provider.llmDivider": "AI · Context-Aware", + "dashboard.translate.provider.llmDividerPro": "AI · Context-Aware (Pro)", + "dashboard.translate.provider.upgrade": "Upgrade to Pro", + "dashboard.translate.provider.upgradeSuffix": "to unlock AI translation", + "dashboard.translate.provider.tabStandard": "Standard", + "dashboard.translate.provider.tabLLM": "AI Multi-Models", + "dashboard.translate.translateImages": "Translate images", + "dashboard.translate.translateImagesDesc": "Extract and translate text inside images (vision required)", + "dashboard.translate.trust.zeroRetention": "Zero retention", + "dashboard.translate.trust.deletedAfter": "Files deleted after processing", + "dashboard.translate.actions.uploading": "Uploading…", + "dashboard.translate.actions.translate": "Translate", + "dashboard.translate.actions.filePrefix": "File: ", + "dashboard.translate.actions.cancel": "Cancel", + "dashboard.translate.actions.tryAgain": "Try Again", + "dashboard.translate.steps.uploading": "Uploading file…", + "dashboard.translate.steps.starting": "Starting translation…", + "dashboard.translate.complete.title": "Translation complete!", + "dashboard.translate.complete.descNamed": "Your file {name} has been translated successfully.", + "dashboard.translate.complete.descGeneric": "Your file has been translated successfully.", + "dashboard.translate.complete.downloading": "Downloading…", + "dashboard.translate.complete.download": "Download", + "dashboard.translate.complete.newTranslation": "New Translation", + "dashboard.translate.complete.toastOkTitle": "Success", + "dashboard.translate.complete.toastOkDesc": "{name} has been downloaded successfully.", + "dashboard.translate.complete.toastFailTitle": "Failed", + "dashboard.translate.complete.toastFailDesc": "Translation failed. Please try again.", + "dashboard.translate.sourceDocument": "Source Document", + "dashboard.translate.configuration": "Configuration", + "dashboard.translate.translating": "Translation in progress", + "dashboard.translate.liveMonitor": "Live Monitor", + "dashboard.translate.summary": "Summary", + "dashboard.translate.engine": "Engine", + "dashboard.translate.confidence": "Confidence", + "dashboard.translate.cancel": "Cancel", + "dashboard.translate.segments": "Segments", + "dashboard.translate.characters": "Characters", + "dashboard.translate.elapsed": "Elapsed", + "dashboard.translate.segPerMin": "Seg/min", + "dashboard.translate.highQuality": "High quality", + "dashboard.translate.quality": "Quality", + "dashboard.translate.completed": "Translation complete", + "dashboard.translate.replace": "Replace", + "dashboard.translate.pdfMode.title": "PDF Translation Mode", + "dashboard.translate.pdfMode.preserveLayout": "Preserve Layout", + "dashboard.translate.pdfMode.textOnly": "Text Only", + "dashboard.translate.pdfMode.preserveLayoutDesc": "Keeps images, tables & formatting. Best for simple PDFs.", + "dashboard.translate.pdfMode.textOnlyDesc": "Translates all text perfectly. Clean output, no layout issues.", + "dashboard.translate.pipeline.upload": "Upload", + "dashboard.translate.pipeline.analyze": "Analyze", + "dashboard.translate.pipeline.translate": "Translation", + "dashboard.translate.pipeline.rebuild": "Rebuild", + "dashboard.translate.pipeline.finalize": "Finalize", + "dashboard.translate.progress.processingFallback": "Processing…", + "dashboard.translate.progress.connectionLost": "Connection lost. Retrying…", + "dashboard.translate.progress.failedTitle": "Translation failed", + "dashboard.translate.error.unexpected": "An unexpected error occurred. Please try again.", + "dashboard.translate.error.noResult": "Translation produced no results. Verify the document contains text, then try again or choose another engine.", + "dashboard.translate.error.apiKey": "Invalid or missing API key. Contact the administrator to configure API keys.", + "dashboard.translate.error.quota": "Usage limit reached. Try again in a few minutes or choose another engine.", + "dashboard.translate.error.timeout": "Connection to the translation service timed out. Check your network and try again.", + "dashboard.translate.error.sessionExpired": "Session expired. Click Retry to restart the translation.", + "dashboard.translate.error.empty": "The document appears empty or contains no translatable text (scanned PDF image?).", + "dashboard.translate.error.unsupported": "Unsupported file format or corrupted file.", + "dashboard.translate.error.connection": "Connection lost. Check your network and try again.", + "dashboard.translate.error.generic": "Translation failed: {detail}", + "dashboard.translate.error.title": "Translation failed", + "dashboard.translate.retry": "Retry translation", + "dashboard.translate.newFile": "New file", + "dashboard.translate.modeAI": "AI Mode", + "dashboard.translate.modeClassic": "Classic Mode", + "dashboard.translate.glossaryLLMHint": "Glossaries available in AI mode", + "dashboard.translate.submitting": "Submitting...", + "dashboard.translate.submit": "Start translation", + "dashboard.translate.noFile": "Upload a file first", + "dashboard.translate.noTargetLang": "Select a target language", + "dashboard.topbar.interfaceLabel": "Translation Interface", + "dashboard.topbar.premiumAccess": "Premium Access", + "dashboard.checkoutSyncError": "Error syncing payment.", + "dashboard.networkRefresh": "Network error. Please refresh the page.", + "dashboard.continueToTranslate": "Continue to translation" +} diff --git a/frontend/src/lib/i18n/messages/en/fileUploader.json b/frontend/src/lib/i18n/messages/en/fileUploader.json new file mode 100644 index 0000000..476d5d6 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/fileUploader.json @@ -0,0 +1,31 @@ +{ + "fileUploader.uploadDocument": "Upload Document", + "fileUploader.uploadDesc": "Drag and drop or click to select a file (Excel, Word, PowerPoint)", + "fileUploader.dropHere": "Drop your file here...", + "fileUploader.dragAndDrop": "Drag & drop your document here", + "fileUploader.orClickBrowse": "or click to browse", + "fileUploader.preview": "Preview", + "fileUploader.translationOptions": "Translation Options", + "fileUploader.configureSettings": "Configure your translation settings", + "fileUploader.targetLanguage": "Target Language", + "fileUploader.selectLanguage": "Select language", + "fileUploader.translationProvider": "Translation Provider", + "fileUploader.selectProvider": "Select provider", + "fileUploader.advancedOptions": "Advanced Options", + "fileUploader.translateImages": "Translate Images", + "fileUploader.translating": "Translating...", + "fileUploader.translateDocument": "Translate Document", + "fileUploader.processing": "Processing...", + "fileUploader.translationError": "Translation Error", + "fileUploader.translationComplete": "Translation Complete!", + "fileUploader.translationCompleteDesc": "Your document has been translated successfully while preserving all formatting.", + "fileUploader.download": "Download Translated Document", + "fileUploader.webgpuUnsupported": "WebGPU is not supported in this browser. Please use Chrome 113+ or Edge 113+.", + "fileUploader.webllmNotLoaded": "WebLLM model not loaded. Go to Settings > Translation Services to load a model first.", + "fileUploader.extracting": "Extracting texts from document...", + "fileUploader.noTranslatable": "No translatable text found in document", + "fileUploader.foundTexts": "Found {count} texts to translate", + "fileUploader.translatingItem": "Translating {current}/{total}: \\\"{preview}\\\"", + "fileUploader.reconstructing": "Reconstructing document...", + "fileUploader.translatingLocally": "Translating locally with WebLLM..." +} diff --git a/frontend/src/lib/i18n/messages/en/forgotPassword.json b/frontend/src/lib/i18n/messages/en/forgotPassword.json new file mode 100644 index 0000000..0ac67c8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/forgotPassword.json @@ -0,0 +1,14 @@ +{ + "forgotPassword.enterEmail": "Please enter your email address", + "forgotPassword.error": "An error occurred", + "forgotPassword.title": "Forgot Password", + "forgotPassword.checkEmail": "Check your inbox", + "forgotPassword.subtitle": "Enter your email to receive a reset link", + "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", + "forgotPassword.emailLabel": "Email address", + "forgotPassword.emailPlaceholder": "you@example.com", + "forgotPassword.sending": "Sending...", + "forgotPassword.sendLink": "Send reset link", + "forgotPassword.backToLogin": "Back to login", + "forgotPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/en/glossaries.json b/frontend/src/lib/i18n/messages/en/glossaries.json new file mode 100644 index 0000000..e472503 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/glossaries.json @@ -0,0 +1,189 @@ +{ + "glossaries.yourGlossaries": "Your glossaries", + "glossaries.title": "Glossaries & Context", + "glossaries.description": "Manage your glossaries and context instructions for more accurate translations.", + "glossaries.createNew": "Create new", + "glossaries.empty": "No glossaries yet", + "glossaries.emptyDesc": "Create your first glossary or load a professional preset above", + "glossaries.defineTerms": "terms", + "glossaries.aboutTitle": "About glossaries", + "glossaries.aboutDesc": "Glossaries let you define exact translations for specific terms. When you translate a document, the glossary terms are used to ensure consistent and accurate translations.", + "glossaries.aboutFormat": "Each term has a source word and translations in multiple languages. Select a glossary in the translation page to apply it.", + "glossaries.toast.created": "Glossary created", + "glossaries.toast.createdDesc": "The glossary \\\"{name}\\\" has been created.", + "glossaries.toast.imported": "Glossary imported", + "glossaries.toast.importedDesc": "The glossary \\\"{name}\\\" has been imported.", + "glossaries.toast.updated": "Glossary updated", + "glossaries.toast.updatedDesc": "The glossary \\\"{name}\\\" has been updated.", + "glossaries.toast.deleted": "Glossary deleted", + "glossaries.toast.deletedDesc": "The glossary has been deleted.", + "glossaries.toast.error": "Error", + "glossaries.toast.errorCreate": "Failed to create glossary", + "glossaries.toast.errorImport": "Failed to import glossary", + "glossaries.toast.errorUpdate": "Failed to update glossary", + "glossaries.toast.errorDelete": "Failed to delete glossary", + "glossaries.dialog.title": "New glossary", + "glossaries.dialog.description": "Create a glossary for your translations", + "glossaries.dialog.nameLabel": "Name", + "glossaries.dialog.namePlaceholder": "My glossary", + "glossaries.dialog.tabTemplates": "Templates", + "glossaries.dialog.tabFile": "File", + "glossaries.dialog.tabManual": "Manual", + "glossaries.dialog.cancel": "Cancel", + "glossaries.dialog.creating": "Creating…", + "glossaries.dialog.importing": "Importing…", + "glossaries.dialog.importBtn": "Import", + "glossaries.dialog.selectPrompt": "Select", + "glossaries.dialog.createBtn": "Create", + "glossaries.dialog.createEmpty": "Create empty", + "glossaries.dialog.terms": "terms", + "glossaries.dialog.templatesDesc": "Choose a predefined template", + "glossaries.dialog.templatesEmpty": "No templates available", + "glossaries.dialog.dropTitle": "Drag a CSV file here", + "glossaries.dialog.dropOr": "or", + "glossaries.dialog.dropFormats": "CSV, TSV, TXT", + "glossaries.termEditor.addTerm": "Add Term", + "glossaries.termEditor.maxReached": "Maximum {max} terms per glossary reached.", + "glossaries.dialog.formatTitle": "Format", + "glossaries.dialog.formatDesc": "source,target (one per line)", + "glossaries.dialog.formatNote": "First line skipped if header detected", + "glossaries.dialog.errorFormat": "Unsupported format", + "glossaries.dialog.errorSize": "File too large", + "glossaries.dialog.errorEmpty": "Empty file", + "glossaries.dialog.errorRead": "Read error", + "glossaries.dialog.parsing": "Parsing…", + "glossaries.dialog.termsImported": "terms imported", + "glossaries.dialog.changeFile": "Change file", + "glossaries.dialog.retry": "Retry", + "glossaries.edit.title": "Edit Glossary", + "glossaries.edit.description": "Update the glossary name, language pair, and terms.", + "glossaries.edit.nameLabel": "Glossary Name", + "glossaries.edit.namePlaceholder": "Enter glossary name...", + "glossaries.edit.sourceLang": "Source language", + "glossaries.edit.targetLang": "Target language", + "glossaries.edit.termsLabel": "Terms ({count} valid)", + "glossaries.edit.exportCsv": "Export CSV", + "glossaries.edit.importCsv": "Import CSV", + "glossaries.edit.cancel": "Cancel", + "glossaries.edit.saving": "Saving...", + "glossaries.edit.saveChanges": "Save Changes", + "glossaries.edit.importFailedTitle": "Import failed", + "glossaries.edit.importFailedMaxDesc": "CSV contains {count} terms, but maximum is {max}. Please reduce the number of terms.", + "glossaries.edit.importSuccessTitle": "Import successful", + "glossaries.edit.importSuccessDesc": "{count} terms imported successfully.", + "glossaries.edit.importFailedEmptyDesc": "No valid terms found in CSV file.", + "glossaries.edit.importFailedReadDesc": "Failed to read CSV file.", + "glossaries.delete.title": "Delete Glossary", + "glossaries.delete.description": "Are you sure you want to delete this glossary?", + "glossaries.delete.warning": "This action cannot be undone", + "glossaries.delete.warningDesc": "All term pairs will be permanently removed.", + "glossaries.delete.cancel": "Cancel", + "glossaries.delete.deleting": "Deleting...", + "glossaries.delete.deleteBtn": "Delete", + "glossaries.upgrade.title": "Glossaries", + "glossaries.upgrade.description": "Customize your translations with custom terminology", + "glossaries.upgrade.feature1": "Create multiple glossaries", + "glossaries.upgrade.feature2": "Define source→target term pairs", + "glossaries.upgrade.feature3": "Import/export via CSV", + "glossaries.upgrade.feature4": "Apply to LLM translations", + "glossaries.upgrade.proFeatureBefore": "Glossaries are a ", + "glossaries.upgrade.proFeatureAfter": " feature. Upgrade to unlock custom terminology.", + "glossaries.upgrade.proLabel": "Pro", + "glossaries.upgrade.upgradeBtn": "Upgrade to Pro", + "glossaries.loading": "Loading...", + "glossaries.howItWorks.title": "How these settings are used", + "glossaries.howItWorks.step1Title": "Configure here", + "glossaries.howItWorks.step1Desc": "Write your context instructions or create/import a glossary of terms.", + "glossaries.howItWorks.step2Title": "Activate in Translate", + "glossaries.howItWorks.step2Desc": "On the translation page, in the right column, select your glossary.", + "glossaries.howItWorks.warning": "Context instructions apply automatically to all your AI translations once saved. Glossaries must be manually selected on the Translate page.", + "glossaries.howItWorks.goToTranslate": "Go to Translate", + "glossaries.status.unsaved": "Unsaved", + "glossaries.status.active": "Active · applies to all AI translations", + "glossaries.status.inactive": "Inactive", + "glossaries.instructions.whatForBold": "What is it for?", + "glossaries.instructions.whatForDesc": "These instructions are automatically sent to the AI before each translation, without you having to do anything on the Translate page. Use them to guide the style, register or general terminology.", + "glossaries.instructions.example": "Example: \\\"You translate financial reports. Be formal, precise and keep all figures.\\\"", + "glossaries.instructions.charCount": "{count} characters", + "glossaries.instructions.emptyHint": "Empty — no instructions sent to the AI", + "glossaries.instructions.clearAll": "Clear all", + "glossaries.instructions.saving": "Saving...", + "glossaries.instructions.saved": "Saved", + "glossaries.presets.whatForBold": "What is it for?", + "glossaries.presets.whatForDesc": "Clicking a card creates a pre-filled glossary with domain-specific terms. This glossary will appear in your glossaries below, and you can manually select it on the Translate page to force precise term translations.", + "glossaries.presets.clickHint": "Click a card → glossary created → select it in Translate", + "glossaries.presets.creating": "Creating...", + "glossaries.presets.alreadyImported": "Imported", + "glossaries.presets.it.title": "IT / Software", + "glossaries.presets.it.desc": "Development, infrastructure, DevOps", + "glossaries.presets.legal.title": "Legal / Contracts", + "glossaries.presets.legal.desc": "Business law, litigation", + "glossaries.presets.medical.title": "Medical / Health", + "glossaries.presets.medical.desc": "Pharmacology, surgery, diagnosis", + "glossaries.presets.finance.title": "Finance / Accounting", + "glossaries.presets.finance.desc": "IFRS, balance sheets, taxation", + "glossaries.presets.marketing.title": "Marketing / Advertising", + "glossaries.presets.marketing.desc": "Digital, branding, analytics", + "glossaries.presets.hr.title": "HR / Human Resources", + "glossaries.presets.hr.desc": "Contracts, policies, recruitment", + "glossaries.presets.scientific.title": "Scientific / Research", + "glossaries.presets.scientific.desc": "Publications, theses, articles", + "glossaries.presets.ecommerce.title": "E-commerce / Sales", + "glossaries.presets.ecommerce.desc": "Online stores, catalogs, CRM", + "glossaries.grid.title": "Your", + "glossaries.grid.titleHighlight": "glossaries", + "glossaries.grid.countWithAction": "{count} glossary({plural}) — click a card to edit", + "glossaries.grid.emptyAction": "Create your first glossary or import a preset above", + "glossaries.grid.activeTranslation": "Active translation:", + "glossaries.grid.goToTranslate": "Go to Translate to activate", + "glossaries.badge.compatible": "Compatible", + "glossaries.badge.otherTarget": "Other target", + "glossaries.card.editTerms": "Edit terms", + "glossaries.card.created": "Created", + "glossaries.card.term": "term", + "glossaries.card.delete": "Delete", + "glossaries.grid.searchPlaceholder": "Search a glossary…", + "glossaries.grid.noResults": "No results for this search.", + "glossaries.detail.backToList": "Back to glossaries", + "glossaries.detail.save": "Save", + "glossaries.detail.savedTitle": "Saved", + "glossaries.detail.savedDesc": "The glossary has been updated.", + "glossaries.detail.settingsTitle": "Settings", + "glossaries.detail.sourceLang": "Source language", + "glossaries.detail.targetLang": "Target language", + "glossaries.detail.termsTitle": "Terms", + "glossaries.detail.terms": "terms", + "glossaries.detail.searchTerms": "Filter…", + "glossaries.detail.noTerms": "No terms yet.", + "glossaries.detail.addFirstTerm": "Add the first term", + "glossaries.detail.addTerm": "Add a term", + "glossaries.detail.maxReached": "Maximum limit reached", + "glossaries.detail.source": "Source", + "glossaries.detail.target": "Target", + "glossaries.detail.sourcePlaceholder": "source term", + "glossaries.detail.targetPlaceholder": "target term", + "glossaries.detail.csvTitle": "CSV", + "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", + "glossaries.detail.export": "Export", + "glossaries.detail.import": "Import", + "glossaries.detail.dangerTitle": "Danger zone", + "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", + "glossaries.detail.deleteGlossary": "Delete this glossary", + "glossaries.detail.confirmDelete": "Confirm deletion?", + "glossaries.detail.confirm": "Confirm", + "glossaries.detail.cancel": "Cancel", + "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", + "glossaries.detail.sourceLocked": "fixed", + "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", + "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", + "glossaries.detail.notFoundTitle": "Glossary not found", + "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", + "glossaries.detail.maxTermsTitle": "Limit reached", + "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", + "glossaries.detail.importEmptyTitle": "Empty file", + "glossaries.detail.importEmptyDesc": "No terms detected in this file.", + "glossaries.detail.importedTitle": "Imported", + "glossaries.detail.importedDesc": "{count} terms imported.", + "glossaries.detail.importErrorTitle": "Read error", + "glossaries.detail.importErrorDesc": "Unable to read the file." +} diff --git a/frontend/src/lib/i18n/messages/en/index.ts b/frontend/src/lib/i18n/messages/en/index.ts new file mode 100644 index 0000000..876199f --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/index.ts @@ -0,0 +1,60 @@ +// Auto-generated by scripts/generate_i18n_index.py +// Merges all namespace JSON files for locale "en". + +import admin from "./admin.json"; +import apiKeys from "./apiKeys.json"; +import auth from "./auth.json"; +import checkout from "./checkout.json"; +import common from "./common.json"; +import context from "./context.json"; +import cookieConsent from "./cookieConsent.json"; +import dashboard from "./dashboard.json"; +import fileUploader from "./fileUploader.json"; +import forgotPassword from "./forgotPassword.json"; +import glossaries from "./glossaries.json"; +import landing from "./landing.json"; +import langSelector from "./langSelector.json"; +import layout from "./layout.json"; +import login from "./login.json"; +import memento from "./memento.json"; +import pricing from "./pricing.json"; +import profile from "./profile.json"; +import providerSelector from "./providerSelector.json"; +import providerTheme from "./providerTheme.json"; +import register from "./register.json"; +import resetPassword from "./resetPassword.json"; +import services from "./services.json"; +import settings from "./settings.json"; +import translate from "./translate.json"; +import translateComplete from "./translateComplete.json"; + +const messages: Record = { + ...admin, + ...apiKeys, + ...auth, + ...checkout, + ...common, + ...context, + ...cookieConsent, + ...dashboard, + ...fileUploader, + ...forgotPassword, + ...glossaries, + ...landing, + ...langSelector, + ...layout, + ...login, + ...memento, + ...pricing, + ...profile, + ...providerSelector, + ...providerTheme, + ...register, + ...resetPassword, + ...services, + ...settings, + ...translate, + ...translateComplete, +}; + +export default messages; diff --git a/frontend/src/lib/i18n/messages/en/landing.json b/frontend/src/lib/i18n/messages/en/landing.json new file mode 100644 index 0000000..c4c0aa0 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/landing.json @@ -0,0 +1,152 @@ +{ + "landing.nav.why": "Why Us?", + "landing.nav.formats": "Formats", + "landing.nav.pricing": "Pricing", + "landing.nav.login": "Log in", + "landing.nav.startFree": "Start Free", + "landing.hero.tag": "Professional Document AI", + "landing.hero.titleLine1": "Translate your documents.", + "landing.hero.titleLine2": "Keep the formatting perfect.", + "landing.hero.description": "The only translator that preserves SmartArt, charts, tables of contents, shapes, and complex layouts — exactly as they were.", + "landing.hero.ctaMain": "Start Free — 2 docs/month", + "landing.hero.ctaSec": "See Offers", + "landing.hero.deleted": "Files deleted after 60 min", + "landing.hero.noHidden": "No hidden fees", + "landing.hero.preview": "Preview before payment", + "landing.hero.formattedOk": "Formatting OK", + "landing.hero.aiActive": "AI Translation active", + "landing.steps.title": "How it works?", + "landing.steps.subtitle": "Three steps. Zero formatting loss.", + "landing.steps.step1.num": "01", + "landing.steps.step1.title": "Upload your file", + "landing.steps.step1.desc": "Drag & drop your Excel, Word, PowerPoint or PDF document.", + "landing.steps.step2.num": "02", + "landing.steps.step2.title": "Pick language & engine", + "landing.steps.step2.desc": "Select target language and engine — classic or context-aware AI.", + "landing.steps.step3.num": "03", + "landing.steps.step3.title": "Download the result", + "landing.steps.step3.desc": "Get your translated document with formatting identical to the original.", + "landing.features.tag": "AI Translation Engine", + "landing.features.title": "Translation that understands your craft", + "landing.features.description": "Our AI models analyze context, respect your terminology, and even translate text inside images.", + "landing.features.context.title": "Industry Context", + "landing.features.context.desc": "Describe your field and get tailored translations, not generic ones.", + "landing.features.glossary.title": "Industry Glossaries", + "landing.features.glossary.desc": "Define your technical terms. CTA stays 'Air Handling Unit', never 'Call To Action'.", + "landing.features.vision.title": "Image Vision", + "landing.features.vision.desc": "Text embedded in images, diagrams and charts is detected and translated.", + "landing.features.demo.source": "Source (FR)", + "landing.features.demo.google": "Google Translate", + "landing.features.demo.ours": "Our AI", + "landing.layout.title": "Your formatting,", + "landing.layout.title2": "perfectly preserved", + "landing.layout.subtitle": "Other translators break your layout. We don't.", + "landing.layout.p1.title": "SmartArt & Diagrams", + "landing.layout.p1.desc": "Org charts, flowcharts, hierarchies — all translated identically.", + "landing.layout.p2.title": "Tables of Contents", + "landing.layout.p2.desc": "TOC entries, page numbers and cross-references updated correctly.", + "landing.layout.p3.title": "Charts & Graphs", + "landing.layout.p3.desc": "Titles, axis labels, legends and series names — everything is translated.", + "landing.layout.p4.title": "Shapes & Text Boxes", + "landing.layout.p4.desc": "Rectangles, rounded blocks, callouts — localized everywhere.", + "landing.layout.p5.title": "Headers & Footers", + "landing.layout.p5.desc": "Headers, footers and footnotes are never missed.", + "landing.layout.p6.title": "130+ Languages", + "landing.layout.p6.desc": "Google Translate, DeepL and professional-grade AI engines.", + "landing.formats.title": "Every format,", + "landing.formats.title2": "every element", + "landing.formats.subtitle": "We translate what others miss. Your business deserves irreproachable documentation.", + "landing.formats.word.name": "Word", + "landing.formats.word.i1": "Paragraphs & headings", + "landing.formats.word.i2": "Tables & charts", + "landing.formats.word.i3": "SmartArt diagrams", + "landing.formats.word.i4": "Table of contents", + "landing.formats.word.i5": "Headers & footers", + "landing.formats.word.i6": "Shapes & text boxes", + "landing.formats.word.i7": "Footnotes & endnotes", + "landing.formats.excel.name": "Excel", + "landing.formats.excel.i1": "Cell values", + "landing.formats.excel.i2": "Sheet names", + "landing.formats.excel.i3": "Charts & labels", + "landing.formats.excel.i4": "Headers & footers", + "landing.formats.excel.i5": "Merged cells preserved", + "landing.formats.pptx.name": "PowerPoint", + "landing.formats.pptx.i1": "Slide text & notes", + "landing.formats.pptx.i2": "Charts & diagrams", + "landing.formats.pptx.i3": "Shapes & text boxes", + "landing.formats.pptx.i4": "Master layouts", + "landing.formats.pptx.i5": "Animations preserved", + "landing.formats.pdf.name": "PDF", + "landing.formats.pdf.i1": "Text-based PDFs", + "landing.formats.pdf.i2": "Layout preserved", + "landing.formats.pdf.i3": "Images kept in place", + "landing.formats.pdf.i4": "Tables maintained", + "landing.formats.pdf.i5": "Output as DOCX or PDF", + "landing.pricing.title": "Simple, honest pricing", + "landing.pricing.subtitle": "What you see is what you pay. No hidden fees.", + "landing.pricing.monthly": "Monthly", + "landing.pricing.annual": "Annual", + "landing.pricing.bestValue": "Most Popular", + "landing.pricing.month": "/month", + "landing.pricing.footer": "The displayed price is the price you pay. No hidden fees after translation.", + "landing.pricing.starter.name": "Starter", + "landing.pricing.starter.desc": "For individuals and small projects", + "landing.pricing.starter.f1": "50 documents / month", + "landing.pricing.starter.f2": "Up to 50 pages per doc", + "landing.pricing.starter.f3": "Google Translate + DeepL", + "landing.pricing.starter.f4": "Files up to 10 MB", + "landing.pricing.starter.cta": "Get Started", + "landing.pricing.pro.name": "Pro", + "landing.pricing.pro.desc": "For demanding professionals", + "landing.pricing.pro.f1": "200 documents / month", + "landing.pricing.pro.f2": "Up to 200 pages per doc", + "landing.pricing.pro.f3": "AI-powered translation", + "landing.pricing.pro.f4": "Google + DeepL included", + "landing.pricing.pro.f5": "Custom glossaries & prompts", + "landing.pricing.pro.f6": "Priority support", + "landing.pricing.pro.cta": "Try Pro", + "landing.pricing.business.name": "Business", + "landing.pricing.business.desc": "For teams with high-volume needs", + "landing.pricing.business.f1": "1,000 documents / month", + "landing.pricing.business.f2": "Up to 500 pages per doc", + "landing.pricing.business.f3": "Premium AI (Claude)", + "landing.pricing.business.f4": "All providers + API access", + "landing.pricing.business.f5": "Webhooks & automation", + "landing.pricing.business.f6": "5 team seats", + "landing.pricing.business.cta": "Contact Us", + "landing.pricing.free.name": "Free", + "landing.pricing.free.desc": "Perfect to discover the app", + "landing.pricing.free.cta": "Choose this plan", + "landing.pricing.enterprise.name": "Enterprise", + "landing.pricing.enterprise.desc": "Custom solutions for large organizations", + "landing.pricing.enterprise.cta": "Contact us", + "landing.cta.title": "Start translating in 30 seconds", + "landing.cta.subtitle": "No credit card required. Try for free now and bring your multilingual documents back to life.", + "landing.cta.button": "Create Free Account", + "landing.cta.secure": "Secured by AES-256 encryption", + "landing.footer.desc": "Expert in intelligent document translation. We blend the art of layout with the science of contextual AI.", + "landing.footer.product": "Product", + "landing.footer.resources": "Resources", + "landing.footer.legal": "Legal", + "landing.footer.rights": "© 2026 Wordly.art — All rights reserved.", + "landing.hero.contextEngine": "Translation detected: Technical maintenance term for HVAC systems...", + "landing.hero.liveAnalysis": "Live Analysis", + "landing.hero.termsDetected": "terms detected", + "landing.steps.process": "PROCESS", + "landing.translate.newProject": "New Project", + "landing.translate.title": "Translate a document", + "landing.translate.subtitle": "Import a file and choose the target language", + "landing.translate.sourceDocument": "Source Document", + "landing.translate.configuration": "Configuration", + "landing.translate.sourceLang": "Source Language", + "landing.translate.targetLang": "Target Language", + "landing.translate.provider": "Provider", + "landing.translate.startTranslation": "Start Translation", + "landing.translate.zeroRetention": "Zero retention", + "landing.translate.filesDeleted": "Files deleted after processing", + "landing.translate.dropHere": "Drag & drop here", + "landing.translate.supportedFormats": "DOCX, XLSX, PPTX or PDF files supported", + "landing.translate.aiAnalysis": "Active AI Analysis", + "landing.translate.processing": "Processing", + "landing.translate.preservingLayout": "Your layout is being preserved" +} diff --git a/frontend/src/lib/i18n/messages/en/langSelector.json b/frontend/src/lib/i18n/messages/en/langSelector.json new file mode 100644 index 0000000..fa29420 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/langSelector.json @@ -0,0 +1,7 @@ +{ + "langSelector.search": "Search...", + "langSelector.noResults": "No results", + "langSelector.source": "Source", + "langSelector.target": "Target", + "langSelector.swap": "Swap" +} diff --git a/frontend/src/lib/i18n/messages/en/layout.json b/frontend/src/lib/i18n/messages/en/layout.json new file mode 100644 index 0000000..2adb9da --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/layout.json @@ -0,0 +1,5 @@ +{ + "layout.nav.apiAccess": "API Access", + "layout.footer.terms": "Terms", + "layout.footer.privacy": "Privacy" +} diff --git a/frontend/src/lib/i18n/messages/en/login.json b/frontend/src/lib/i18n/messages/en/login.json new file mode 100644 index 0000000..727b4fe --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/login.json @@ -0,0 +1,18 @@ +{ + "login.errorTitle": "Login Error", + "login.welcomeBack": "Welcome back", + "login.signInToContinue": "Sign in to continue translating", + "login.email": "Email", + "login.emailPlaceholder": "you@example.com", + "login.password": "Password", + "login.forgotPassword": "Forgot password?", + "login.passwordPlaceholder": "••••••••", + "login.signingIn": "Signing in...", + "login.signIn": "Sign In", + "login.noAccount": "Don't have an account?", + "login.signUpFree": "Sign up for free", + "login.orContinueWith": "or continue with email", + "login.google.connecting": "Connecting…", + "login.google.errorGeneric": "Something went wrong with Google sign-in.", + "login.google.errorFailed": "Google sign-in failed. Please try again." +} diff --git a/frontend/src/lib/i18n/messages/en/memento.json b/frontend/src/lib/i18n/messages/en/memento.json new file mode 100644 index 0000000..bffe008 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/memento.json @@ -0,0 +1,6 @@ +{ + "memento.title": "Discover Momento", + "memento.slogan": "Momento is more than just a notes application. It's an intelligent ecosystem that connects, analyzes, and develops your ideas in real-time using 6 AI agents and cutting-edge semantic search.", + "memento.ctaFree": "Start for free", + "memento.ctaMore": "Learn more" +} diff --git a/frontend/src/lib/i18n/messages/en/pricing.json b/frontend/src/lib/i18n/messages/en/pricing.json new file mode 100644 index 0000000..9b2bc0f --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/pricing.json @@ -0,0 +1,151 @@ +{ + "pricing.nav.back": "Back", + "pricing.nav.home": "Home", + "pricing.nav.mySubscription": "My Subscription", + "pricing.header.badge": "AI Models Updated — March 2026", + "pricing.header.title": "A plan for every need", + "pricing.header.subtitle": "Translate your Word, Excel and PowerPoint documents while preserving the original layout. No API key required.", + "pricing.billing.monthly": "Monthly", + "pricing.billing.yearly": "Yearly", + "pricing.plans.free.name": "Free", + "pricing.plans.starter.name": "Starter", + "pricing.plans.pro.name": "Pro", + "pricing.plans.business.name": "Business", + "pricing.plans.enterprise.name": "Enterprise", + "pricing.plans.free.description": "Perfect for discovering the app", + "pricing.plans.starter.description": "For individuals and small projects", + "pricing.plans.pro.description": "For professionals and growing teams", + "pricing.plans.business.description": "For teams and organizations", + "pricing.plans.enterprise.description": "Custom solutions for large organizations", + "pricing.plans.pro.highlight": "Most popular", + "pricing.plans.pro.badge": "POPULAR", + "pricing.plans.enterprise.badge": "ON REQUEST", + "pricing.plans.free.feat1": "5 documents / month", + "pricing.plans.free.feat2": "Up to 15 pages per document", + "pricing.plans.free.feat3": "Google Translation included", + "pricing.plans.free.feat4": "All languages (130+)", + "pricing.plans.free.feat5": "Community support", + "pricing.plans.starter.feat1": "50 documents / month", + "pricing.plans.starter.feat2": "Up to 50 pages per document", + "pricing.plans.starter.feat3": "Google Translation + DeepL", + "pricing.plans.starter.feat4": "Files up to 10 MB", + "pricing.plans.starter.feat5": "Email support", + "pricing.plans.starter.feat6": "30-day history", + "pricing.plans.pro.feat1": "200 documents / month", + "pricing.plans.pro.feat2": "Up to 200 pages per document", + "pricing.plans.pro.feat3": "Essential AI Translation", + "pricing.plans.pro.feat4": "Google Translation + DeepL", + "pricing.plans.pro.feat5": "Files up to 25 MB", + "pricing.plans.pro.feat6": "Custom glossaries", + "pricing.plans.pro.feat7": "Priority support", + "pricing.plans.pro.feat8": "90-day history", + "pricing.plans.business.feat1": "1,000 documents / month", + "pricing.plans.business.feat2": "Up to 500 pages per document", + "pricing.plans.business.feat3": "Essential + Premium AI (Claude Haiku)", + "pricing.plans.business.feat4": "All translation providers", + "pricing.plans.business.feat5": "Files up to 50 MB", + "pricing.plans.business.feat6": "API access (10,000 calls/month)", + "pricing.plans.business.feat7": "Notification webhooks", + "pricing.plans.business.feat8": "Dedicated support", + "pricing.plans.business.feat9": "1-year history", + "pricing.plans.business.feat10": "Advanced analytics", + "pricing.plans.enterprise.feat1": "Unlimited documents", + "pricing.plans.enterprise.feat2": "All AI models (GPT-5, Claude Opus 4.6…)", + "pricing.plans.enterprise.feat3": "On-premise or dedicated cloud deployment", + "pricing.plans.enterprise.feat4": "99.9% SLA guaranteed", + "pricing.plans.enterprise.feat5": "24/7 dedicated support", + "pricing.plans.enterprise.feat6": "White-label", + "pricing.plans.enterprise.feat7": "Unlimited teams", + "pricing.plans.enterprise.feat8": "Custom integrations", + "pricing.card.onRequest": "On request", + "pricing.card.free": "Free", + "pricing.card.perMonth": "/month", + "pricing.card.billedYearly": "Billed {price} € / year", + "pricing.card.documents": "Documents", + "pricing.card.pagesMax": "Max pages", + "pricing.card.aiTranslation": "AI Translation", + "pricing.card.unlimited": "Unlimited", + "pricing.card.perMonthStat": "/ month", + "pricing.card.perDoc": "p / doc", + "pricing.card.aiEssential": "Essential", + "pricing.card.aiEssentialPremium": "Essential + Premium", + "pricing.card.aiCustom": "Custom", + "pricing.card.myPlan": "My Plan", + "pricing.card.managePlan": "Manage my plan", + "pricing.card.startFree": "Start for free", + "pricing.card.contactUs": "Contact us", + "pricing.card.choosePlan": "Choose this plan", + "pricing.card.processing": "Processing…", + "pricing.comparison.title": "Detailed comparison", + "pricing.comparison.subtitle": "Everything included in each plan", + "pricing.comparison.feature": "Feature", + "pricing.comparison.docsPerMonth": "Documents / month", + "pricing.comparison.pagesMaxPerDoc": "Max pages / document", + "pricing.comparison.maxFileSize": "Max file size", + "pricing.comparison.googleTranslation": "Google Translation", + "pricing.comparison.deepl": "DeepL", + "pricing.comparison.aiEssential": "Essential AI Translation", + "pricing.comparison.aiPremium": "Premium AI Translation", + "pricing.comparison.apiAccess": "API Access", + "pricing.comparison.priorityProcessing": "Priority processing", + "pricing.comparison.support": "Support", + "pricing.comparison.support.community": "Community", + "pricing.comparison.support.email": "Email", + "pricing.comparison.support.priority": "Priority", + "pricing.comparison.support.dedicated": "Dedicated", + "pricing.comparison.mb": "MB", + "pricing.credits.title": "Additional credits", + "pricing.credits.subtitle": "Need more? Buy credits individually, no subscription.", + "pricing.credits.perPage": "1 credit = 1 translated page.", + "pricing.credits.bestValue": "Best value", + "pricing.credits.unit": "credits", + "pricing.credits.centsPerCredit": "cts / credit", + "pricing.credits.buy": "Buy", + "pricing.trust.encryption.title": "End-to-end encryption", + "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 at rest", + "pricing.trust.languages.title": "130+ languages", + "pricing.trust.languages.sub": "Including Arabic, Persian, Hebrew (RTL)", + "pricing.trust.parallel.title": "Parallel processing", + "pricing.trust.parallel.sub": "Ultra-fast multi-threaded AI", + "pricing.trust.availability.title": "Available 24/7", + "pricing.trust.availability.sub": "99.9% guaranteed uptime", + "pricing.aiModels.title": "Our AI Models — March 2026", + "pricing.aiModels.essential.title": "Essential AI Translation", + "pricing.aiModels.essential.plan": "Pro Plan", + "pricing.aiModels.essential.descPrefix": "Based on", + "pricing.aiModels.essential.descSuffix": "— the most cost-effective AI model of 2026. Quality comparable to frontier models at a fraction of the cost.", + "pricing.aiModels.essential.modelName": "our Essential AI model", + "pricing.aiModels.essential.context": "163K tokens of context", + "pricing.aiModels.essential.value": "Excellent value for money", + "pricing.aiModels.premium.title": "Premium AI Translation", + "pricing.aiModels.premium.plan": "Business Plan", + "pricing.aiModels.premium.descPrefix": "Based on", + "pricing.aiModels.premium.descSuffix": "by Anthropic — accurate on legal, medical and complex technical documents.", + "pricing.aiModels.premium.context": "200K tokens of context", + "pricing.aiModels.premium.precision": "Best accuracy", + "pricing.faq.title": "Frequently asked questions", + "pricing.faq.q1": "Can I change plans at any time?", + "pricing.faq.a1": "Yes. Upgrading is immediate and prorated. Downgrading takes effect at the end of the current period.", + "pricing.faq.q2": "What is \\\"Essential AI Translation\\\"?", + "pricing.faq.a2": "It's our AI engine. It understands your documents' context, preserves layout and handles technical terms much better than classic translation.", + "pricing.faq.q3": "What's the difference between Essential and Premium AI?", + "pricing.faq.a3": "Essential AI uses an optimized model (excellent value for money). Premium AI uses Anthropic's Claude Sonnet 4.6, more accurate on legal, medical and complex technical documents.", + "pricing.faq.q4": "Are my documents kept after translation?", + "pricing.faq.a4": "Translated files are available according to your plan (30 days Starter, 90 days Pro, 1 year Business). They are encrypted at rest and in transit.", + "pricing.faq.q5": "What happens if I exceed my monthly quota?", + "pricing.faq.a5": "You can buy additional credits individually, or upgrade your plan. You are notified at 80% usage.", + "pricing.faq.q6": "Is there a free trial for paid plans?", + "pricing.faq.a6": "The Free plan is permanent and requires no credit card. For Pro and Business plans, contact us for a 14-day trial.", + "pricing.faq.q7": "What file formats are supported?", + "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx), and soon PDF. All plans support the same formats.", + "pricing.cta.title": "Ready to start?", + "pricing.cta.subtitle": "Start for free, no credit card required. Upgrade when you need to.", + "pricing.cta.createAccount": "Create a free account", + "pricing.cta.login": "Sign in", + "pricing.toast.demo": "Demo mode — Stripe is not yet configured. In production, you would be redirected to payment to activate the {planId} plan.", + "pricing.toast.networkError": "Network error. Please try again.", + "pricing.toast.paymentError": "Error creating payment.", + "pricing.dashboard": "Dashboard", + "pricing.okSymbol": "✓", + "pricing.errSymbol": "✕" +} diff --git a/frontend/src/lib/i18n/messages/en/profile.json b/frontend/src/lib/i18n/messages/en/profile.json new file mode 100644 index 0000000..2d07207 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/profile.json @@ -0,0 +1,58 @@ +{ + "profile.header.title": "My Profile", + "profile.header.subtitle": "Manage your account and preferences.", + "profile.tabs.account": "Account", + "profile.tabs.subscription": "Subscription", + "profile.tabs.preferences": "Preferences", + "profile.account.user": "User", + "profile.account.memberSince": "Member since", + "profile.plan.label": "Plan", + "profile.plan.free": "Free", + "profile.plan.starter": "Starter", + "profile.plan.pro": "Pro", + "profile.plan.business": "Business", + "profile.plan.enterprise": "Enterprise", + "profile.plan.pricePerMonth": "{price} €/month", + "profile.subscription.canceling": "Canceling", + "profile.subscription.active": "Active", + "profile.subscription.unknown": "Unknown", + "profile.subscription.accessUntil": "Access until", + "profile.subscription.renewalOn": "Renewal on", + "profile.subscription.upgradePlan": "Upgrade to a paid plan", + "profile.subscription.changePlan": "Change plan", + "profile.subscription.manageBilling": "Manage billing", + "profile.subscription.billingUnavailable": "Billing portal unavailable.", + "profile.subscription.billingError": "Error accessing billing portal.", + "profile.subscription.cancelSuccess": "Subscription canceled. You keep access until the end of the period.", + "profile.subscription.cancelError": "Error during cancellation.", + "profile.subscription.networkError": "Network error.", + "profile.usage.title": "Usage this month", + "profile.usage.resetOn": "Reset on", + "profile.usage.documents": "Documents", + "profile.usage.pages": "Pages", + "profile.usage.extraCredits": "extra credit", + "profile.usage.extraCreditsPlural": "extra credits", + "profile.usage.quotaReached": "Quota reached", + "profile.usage.quotaReachedDesc": "Upgrade to a higher plan to continue.", + "profile.usage.unlockMore": "Unlock more translations with a paid plan.", + "profile.usage.viewPlans": "View plans", + "profile.usage.includedInPlan": "Included in your plan", + "profile.danger.title": "Danger zone", + "profile.danger.description": "Cancellation takes effect at the end of your current period. You keep access until that date.", + "profile.danger.confirm": "Are you sure? This action cannot be undone.", + "profile.danger.confirmCancel": "Confirm cancellation", + "profile.danger.cancelSubscription": "Cancel my subscription", + "profile.danger.keep": "No, keep", + "profile.prefs.interfaceLang": "Interface language", + "profile.prefs.interfaceLangDesc": "The language is automatically detected based on your browser. You can change it manually.", + "profile.prefs.defaultTargetLang": "Default target language", + "profile.prefs.selectLanguage": "Select a language", + "profile.prefs.defaultTargetLangDesc": "This language will be pre-selected for your translations.", + "profile.prefs.save": "Save", + "profile.prefs.theme": "Theme", + "profile.prefs.themeDesc": "Choose the interface appearance", + "profile.prefs.cache": "Cache", + "profile.prefs.cacheDesc": "Clearing the local cache can fix some display issues.", + "profile.prefs.clearing": "Clearing...", + "profile.prefs.clearCache": "Clear cache" +} diff --git a/frontend/src/lib/i18n/messages/en/providerSelector.json b/frontend/src/lib/i18n/messages/en/providerSelector.json new file mode 100644 index 0000000..7839c28 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/providerSelector.json @@ -0,0 +1,7 @@ +{ + "providerSelector.noClassic": "No standard translator available.", + "providerSelector.noLlm": "No AI model configured.", + "providerSelector.costOne": "Cost: 1 credit per page", + "providerSelector.costFive": "Cost: 5 credits per page (Premium factor)", + "providerSelector.unlockContextual": "Unlock premium contextual translation for your entire documents." +} diff --git a/frontend/src/lib/i18n/messages/en/providerTheme.json b/frontend/src/lib/i18n/messages/en/providerTheme.json new file mode 100644 index 0000000..a440896 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/providerTheme.json @@ -0,0 +1,29 @@ +{ + "providerTheme.deepseek.badge": "Essential", + "providerTheme.deepseek.subBadge": "Technical & Eco", + "providerTheme.deepseek.desc": "Ultra-precise and economical translation, ideal for technical documents and code.", + "providerTheme.openai.badge": "Premium", + "providerTheme.openai.subBadge": "High fidelity", + "providerTheme.openai.desc": "The global AI standard. Maximum textual consistency and strict style respect.", + "providerTheme.minimax.badge": "Advanced", + "providerTheme.minimax.subBadge": "Performance", + "providerTheme.minimax.desc": "Incredible execution speed and excellent understanding of complex structures.", + "providerTheme.openrouter.badge": "Express", + "providerTheme.openrouter.subBadge": "Multi-model", + "providerTheme.openrouter.desc": "Unified access to the best open-source models optimized for translation.", + "providerTheme.openrouter_premium.badge": "Ultra", + "providerTheme.openrouter_premium.subBadge": "Maximum context", + "providerTheme.openrouter_premium.desc": "Assisted by state-of-the-art models (GPT-4o, Claude Sonnet 4.6) for long documents.", + "providerTheme.zai.badge": "Specialized", + "providerTheme.zai.subBadge": "Finance & Law", + "providerTheme.zai.desc": "Model fine-tuned for demanding business terminologies (legal, finance).", + "providerTheme.default.badge": "Modern", + "providerTheme.default.subBadge": "AI reasoning", + "providerTheme.default.desc": "Large language model (LLM) translation with advanced semantic analysis.", + "providerTheme.classic.google.label": "Google Translate", + "providerTheme.classic.google.desc": "Ultra-fast translation covering 130+ languages. Recommended for general flows.", + "providerTheme.classic.deepl.label": "DeepL Pro", + "providerTheme.classic.deepl.desc": "High-precision translation renowned for its fluidity and natural formulations.", + "providerTheme.classic.google_cloud.label": "Google Cloud API", + "providerTheme.classic.google_cloud.desc": "Professional cloud engine optimized for processing large volumes of documents." +} diff --git a/frontend/src/lib/i18n/messages/en/register.json b/frontend/src/lib/i18n/messages/en/register.json new file mode 100644 index 0000000..2cc331d --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/register.json @@ -0,0 +1,29 @@ +{ + "register.title": "Create an account", + "register.subtitle": "Start translating for free", + "register.error.failed": "Registration failed", + "register.name.label": "Name", + "register.name.placeholder": "Your name", + "register.name.error": "Name must be at least 2 characters", + "register.email.label": "Email address", + "register.email.placeholder": "you@example.com", + "register.email.error": "Invalid email address", + "register.password.label": "Password", + "register.password.error": "Password must be at least 8 characters with an uppercase, a lowercase and a digit", + "register.password.show": "Show password", + "register.password.hide": "Hide password", + "register.password.strengthLabel": "Strength:", + "register.password.strength.weak": "Weak", + "register.password.strength.medium": "Medium", + "register.password.strength.strong": "Strong", + "register.confirmPassword.label": "Confirm password", + "register.confirmPassword.error": "Passwords do not match", + "register.confirmPassword.show": "Show", + "register.confirmPassword.hide": "Hide", + "register.submit.creating": "Creating account...", + "register.submit.create": "Create my account", + "register.hasAccount": "Already have an account?", + "register.login": "Sign in", + "register.terms.prefix": "By creating an account, you accept our", + "register.terms.link": "terms of service" +} diff --git a/frontend/src/lib/i18n/messages/en/resetPassword.json b/frontend/src/lib/i18n/messages/en/resetPassword.json new file mode 100644 index 0000000..680714f --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/resetPassword.json @@ -0,0 +1,22 @@ +{ + "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", + "resetPassword.passwordMismatch": "Passwords do not match", + "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", + "resetPassword.error": "An error occurred", + "resetPassword.invalidLink": "Invalid link", + "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", + "resetPassword.requestNewLink": "Request new link", + "resetPassword.successTitle": "Password reset", + "resetPassword.newPasswordTitle": "New password", + "resetPassword.successSubtitle": "You will be redirected to login", + "resetPassword.subtitle": "Set your new password", + "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", + "resetPassword.newPassword": "New password", + "resetPassword.showPassword": "Show password", + "resetPassword.hidePassword": "Hide password", + "resetPassword.confirmPassword": "Confirm password", + "resetPassword.resetting": "Resetting...", + "resetPassword.resetPassword": "Reset password", + "resetPassword.backToLogin": "Back to login", + "resetPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/en/services.json b/frontend/src/lib/i18n/messages/en/services.json new file mode 100644 index 0000000..4c849cd --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/services.json @@ -0,0 +1,14 @@ +{ + "services.title": "Translation Providers", + "services.subtitle": "Providers are configured by the administrator. You can see which ones are currently available for your account.", + "services.loading": "Loading providers...", + "services.noProviders": "No providers are currently configured. Contact your administrator.", + "services.classic": "Classic Translation", + "services.llmPro": "LLM · Context-Aware (Pro)", + "services.available": "Available", + "services.model": "Model", + "services.adminOnly.title": "Provider configuration is admin-only", + "services.adminOnly.desc": "API keys, model selection, and provider activation are managed exclusively by the administrator in the admin panel. You never need to enter an API key.", + "services.fallback.google.label": "Google Translate", + "services.fallback.google.desc": "Fast translation, 130+ languages" +} diff --git a/frontend/src/lib/i18n/messages/en/settings.json b/frontend/src/lib/i18n/messages/en/settings.json new file mode 100644 index 0000000..c355a8e --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/settings.json @@ -0,0 +1,20 @@ +{ + "settings.title": "Settings", + "settings.subtitle": "General application configuration", + "settings.formats.title": "Supported formats", + "settings.formats.subtitle": "Document types you can translate", + "settings.formats.formulas": "Formulas", + "settings.formats.styles": "Styles", + "settings.formats.images": "Images", + "settings.formats.headers": "Headers", + "settings.formats.tables": "Tables", + "settings.formats.slides": "Slides", + "settings.formats.notes": "Notes", + "settings.cache.title": "Cache", + "settings.cache.desc": "Clearing the local cache can fix some display issues.", + "settings.cache.clearing": "Clearing...", + "settings.cache.clear": "Clear cache", + "settings.formats.excel.name": "Excel", + "settings.formats.word.name": "Word", + "settings.formats.powerpoint.name": "PowerPoint" +} diff --git a/frontend/src/lib/i18n/messages/en/translate.json b/frontend/src/lib/i18n/messages/en/translate.json new file mode 100644 index 0000000..95716a5 --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/translate.json @@ -0,0 +1,93 @@ +{ + "translate.glossary.selectGlossary": "Select a glossary...", + "translate.mode.label": "Translation Mode", + "translate.mode.classic": "Classic", + "translate.mode.classicDesc": "Fast", + "translate.mode.proLlm": "Pro LLM", + "translate.mode.proLlmDesc": "Context-Aware", + "translate.mode.tooltip": "Upgrade to Pro for LLM translation", + "translate.mode.upgradeLink": "Upgrade to Pro", + "translate.mode.upgradeDesc": "for LLM-powered translations", + "translate.glossary.title": "Glossary", + "translate.glossary.select": "Select a glossary", + "translate.glossary.none": "None", + "translate.glossary.terms": "terms", + "translate.glossary.proOnly": "Upgrade to Pro to use glossaries", + "translate.glossary.myGlossaries": "My glossaries", + "translate.glossary.fromTemplate": "Create from template", + "translate.glossary.noGlossaryForPair": "No glossary for", + "translate.glossary.noGlossaries": "No glossaries yet", + "translate.glossary.loading": "Loading...", + "translate.glossary.classicMode": "Neutral engine without glossary (AI only)", + "translate.glossary.selectPlaceholder": "Select a glossary...", + "translate.glossary.multilingual": "MULTILINGUAL", + "translate.glossary.noGlossaryAvailable": "No glossary available", + "translate.glossary.filterByLang": "Filter by language", + "translate.glossary.active": "Active", + "translate.glossary.inactive": "Inactive", + "translate.glossary.availableTemplates": "Available templates", + "translate.glossary.importing": "Importing...", + "translate.glossary.imported": "(Imported)", + "translate.glossary.noGlossaryForSource": "No glossary or template for source language", + "translate.glossary.createGlossary": "Create a glossary", + "translate.glossary.showAll": "Show all glossaries", + "translate.glossary.activePreview": "Active matches preview:", + "translate.glossary.total": "total", + "translate.glossary.moreTerms": "more terms", + "translate.glossary.noTerms": "No terms in this glossary.", + "translate.glossary.sourceTerm": "Source term", + "translate.glossary.translation": "Translation", + "translate.glossary.addTerm": "Add term", + "translate.glossary.disabledMode": "Neutral engine without glossary applied", + "translate.glossary.addTermError": "Error adding term", + "translate.glossary.networkError": "Network error", + "translate.glossary.importFailed": "Import failed ({status})", + "translate.glossary.helpText": "The glossary forces precise term translation. Choose a glossary whose source language matches your document's original language.", + "translate.glossary.sourceWarning": "Warning: This glossary uses source language", + "translate.glossary.sourceWarningBut": "but your document is configured in", + "translate.glossary.targetWarning": "Target mismatch: This glossary is designed to translate to", + "translate.glossary.targetWarningBut": "but your document targets", + "translate.glossary.targetWarningEnd": "Terms may not be relevant.", + "translate.header.processing": "Processing in progress", + "translate.header.aiActive": "AI analysis active", + "translate.header.aiActiveDesc": "Your layout is being preserved by our contextual engine.", + "translate.header.completed": "Completed", + "translate.header.completedTitle": "Translation completed", + "translate.header.proSpace": "Pro space", + "translate.header.translateDoc": "Translate a document", + "translate.header.translateDocDesc": "Preserve the original layout with our ultra-high-fidelity translation engine.", + "translate.upload.nativeFormat": "Native format", + "translate.fileType.word": "Word (.docx)", + "translate.fileType.excel": "Excel (.xlsx)", + "translate.fileType.slides": "Slides (.pptx)", + "translate.fileType.pdf": "PDF (.pdf)", + "translate.startTranslation": "Start translation", + "translate.submit": "Submitting...", + "translate.chooseTargetLang": "Please choose a target language", + "translate.pleaseLoadFile": "Please upload a file first", + "translate.contextEngineActive": "Contextual engine active", + "translate.phase1": "Phase 1: Initialisation", + "translate.phase2": "Phase 2: Contextual reconstruction", + "translate.stat.segments": "segments", + "translate.stat.precision": "precision", + "translate.stat.speedLabel": "speed", + "translate.stat.turbo": "Turbo", + "translate.stat.time": "time", + "translate.complete.masterQuality": "✓ Master quality", + "translate.download": "Download", + "translate.newTranslation": "+ New translation", + "translate.failedTitle": "Translation error", + "translate.retry": "Retry", + "translate.uploadAnother": "Upload another file", + "translate.monitor": "AI monitor", + "translate.summary": "Summary", + "translate.cancelProcess": "⟳ Cancel the process", + "translate.layoutIntegrity": "Layout integrity", + "translate.secureHundred": "100% SECURE", + "translate.okHundred": "100% OK", + "translate.preserveLayout": "Preserve layout", + "translate.preserveLayoutDesc": "Preserve the layout", + "translate.textOnly": "Text only", + "translate.textOnlyDesc": "Fast translation of text only", + "translate.unavailableStandard": "Unavailable in Standard mode (AI only)" +} diff --git a/frontend/src/lib/i18n/messages/en/translateComplete.json b/frontend/src/lib/i18n/messages/en/translateComplete.json new file mode 100644 index 0000000..b42a7cd --- /dev/null +++ b/frontend/src/lib/i18n/messages/en/translateComplete.json @@ -0,0 +1,6 @@ +{ + "translateComplete.highQuality": "High quality", + "translateComplete.segments": "Segments", + "translateComplete.characters": "Characters", + "translateComplete.confidence": "Confidence" +} diff --git a/frontend/src/lib/i18n/messages/es/admin.json b/frontend/src/lib/i18n/messages/es/admin.json new file mode 100644 index 0000000..5fae644 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/admin.json @@ -0,0 +1,48 @@ +{ + "admin.login.title": "Administración", + "admin.login.required": "Inicio de sesión requerido", + "admin.login.password": "Contraseña de administrador", + "admin.login.connecting": "Conectando...", + "admin.login.access": "Acceder al panel de administración", + "admin.login.restricted": "Restringido a administradores", + "admin.layout.checking": "Verificando autenticación...", + "admin.dashboard.title": "Panel de Administración", + "admin.dashboard.subtitle": "Panel de control del administrador", + "admin.dashboard.refresh": "Actualizar", + "admin.dashboard.refreshTooltip": "Actualizar datos del panel", + "admin.dashboard.config": "Configuración del sistema", + "admin.dashboard.maxFileSize": "Tamaño máximo de archivo:", + "admin.dashboard.translationService": "Servicio de traducción:", + "admin.dashboard.formats": "Formatos:", + "admin.nav.dashboard": "Dashboard", + "admin.nav.users": "Usuarios", + "admin.nav.pricing": "Precios y Stripe", + "admin.nav.providers": "Proveedores", + "admin.nav.system": "Sistema", + "admin.nav.logs": "Registros", + "admin.users.title": "Gestión de Usuarios", + "admin.users.subtitle": "Ver y gestionar cuentas de usuario", + "admin.users.planUpdated": "Plan actualizado", + "admin.users.planChanged": "El plan se ha cambiado a \\\"{plan}\\\" correctamente.", + "admin.users.unknownError": "Error desconocido", + "admin.users.error": "Error", + "admin.users.planUpdateError": "No se pudo actualizar el plan: {message}", + "admin.users.noKeys": "Sin claves", + "admin.users.noKeysDesc": "Este usuario no tiene claves API activas.", + "admin.users.keysRevoked": "Claves revocadas", + "admin.users.keysRevokedDesc": "{count} clave(s) API revocada(s) correctamente.", + "admin.users.revokeError": "No se pudieron revocar las claves: {message}", + "admin.users.retry": "Reintentar", + "admin.system.title": "Sistema", + "admin.system.subtitle": "Supervisar el estado del sistema y gestionar recursos", + "admin.system.quotas": "Cuotas de traducción", + "admin.system.resetQuotas": "Restablecer cuotas mensuales", + "admin.system.resetting": "Restableciendo...", + "admin.system.reset": "Restablecer", + "admin.system.allOperational": "Todos los sistemas operativos", + "admin.system.issuesDetected": "Problemas detectados en el sistema", + "admin.system.waitingData": "Esperando datos...", + "admin.system.purging": "Purgando...", + "admin.system.clean": "Limpiar", + "admin.system.purge": "Purgar" +} diff --git a/frontend/src/lib/i18n/messages/es/apiKeys.json b/frontend/src/lib/i18n/messages/es/apiKeys.json new file mode 100644 index 0000000..0fa9f11 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/apiKeys.json @@ -0,0 +1,72 @@ +{ + "apiKeys.webhook.title": "Intégration Webhook", + "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", + "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", + "apiKeys.webhook.codeParam": "webhook_url", + "apiKeys.title": "Claves API", + "apiKeys.subtitle": "Gestiona tus claves API para el acceso programático a la API de traducción.", + "apiKeys.loading": "Cargando...", + "apiKeys.sectionTitle": "API y automatización", + "apiKeys.sectionDesc": "Genera y gestiona tus claves API para flujos de automatización", + "apiKeys.keysUsed": "{total} de {max} claves usadas", + "apiKeys.maxReached": "Máximo de claves alcanzado. Revoca una clave para generar una nueva.", + "apiKeys.canGenerate": "Puedes generar {count} clave más", + "apiKeys.canGeneratePlural": "Puedes generar {count} claves más", + "apiKeys.generateNew": "Generar nueva clave", + "apiKeys.keyRevoked": "Clave revocada", + "apiKeys.keyRevokedDesc": "La clave API ha sido revocada correctamente.", + "apiKeys.keyNotFound": "Clave no encontrada", + "apiKeys.keyNotFoundDesc": "La clave API ya no existe. Puede que ya haya sido revocada.", + "apiKeys.error": "Error", + "apiKeys.revokeError": "Error al revocar la clave API. Inténtalo de nuevo.", + "apiKeys.limitReached": "Límite alcanzado", + "apiKeys.limitReachedDesc": "Has alcanzado el máximo de 10 claves API. Revoca una clave existente para generar una nueva.", + "apiKeys.proRequired": "Función Pro requerida", + "apiKeys.proRequiredDesc": "Las claves API son una función Pro. Mejora tu cuenta.", + "apiKeys.generateError": "Error al generar la clave API. Inténtalo de nuevo.", + "apiKeys.upgrade.title": "Claves API", + "apiKeys.upgrade.subtitle": "Automatiza tus traducciones con acceso API", + "apiKeys.upgrade.feat1": "Genera claves API ilimitadas", + "apiKeys.upgrade.feat2": "Automatiza la traducción de documentos", + "apiKeys.upgrade.feat3": "Notificaciones por webhook", + "apiKeys.upgrade.feat4": "Modos de traducción LLM", + "apiKeys.upgrade.proFeature": "Las claves API son una función {pro}. Mejora para desbloquear la automatización API.", + "apiKeys.upgrade.pro": "Pro", + "apiKeys.upgrade.cta": "Mejorar a Pro", + "apiKeys.dialog.maxTitle": "Máximo de claves alcanzado", + "apiKeys.dialog.maxDesc": "Has alcanzado el máximo de 10 claves API. Revoca una clave existente antes de generar una nueva.", + "apiKeys.dialog.close": "Cerrar", + "apiKeys.dialog.generated": "¡Clave API generada!", + "apiKeys.dialog.generatedDesc": "Tu nueva clave API ha sido creada. Cópiala ahora, no se volverá a mostrar.", + "apiKeys.dialog.important": "Importante:", + "apiKeys.dialog.importantDesc": "Esta es la única vez que verás esta clave. Guárdala de forma segura.", + "apiKeys.dialog.apiKey": "Clave API", + "apiKeys.dialog.name": "Nombre:", + "apiKeys.dialog.done": "Listo", + "apiKeys.dialog.copied": "Ya he copiado la clave", + "apiKeys.dialog.generateTitle": "Generar nueva clave API", + "apiKeys.dialog.generateDesc": "Crea una nueva clave API para el acceso programático a la API de traducción.", + "apiKeys.dialog.keyName": "Nombre de la clave (opcional)", + "apiKeys.dialog.keyNamePlaceholder": "p.ej., Producción, Staging", + "apiKeys.dialog.keyNameHint": "Un nombre descriptivo para identificar esta clave más tarde.", + "apiKeys.dialog.nameTooLong": "El nombre debe tener {max} caracteres o menos", + "apiKeys.dialog.nameInvalid": "El nombre solo puede contener letras, números, espacios, guiones y guiones bajos", + "apiKeys.dialog.cancel": "Cancelar", + "apiKeys.dialog.generating": "Generando...", + "apiKeys.dialog.generate": "Generar clave", + "apiKeys.table.name": "Nombre", + "apiKeys.table.prefix": "Prefijo", + "apiKeys.table.created": "Creada", + "apiKeys.table.lastUsed": "Último uso", + "apiKeys.table.never": "Nunca", + "apiKeys.table.actions": "Acciones", + "apiKeys.table.revoke": "Revocar", + "apiKeys.table.copyPrefix": "Copiar prefijo de la clave", + "apiKeys.table.revokeKey": "Revocar clave", + "apiKeys.revokeDialog.title": "Revocar clave API", + "apiKeys.revokeDialog.desc": "¿Estás seguro de que quieres revocar la clave \\\"{name}\\\"? Esta acción no se puede deshacer.", + "apiKeys.revokeDialog.confirm": "Sí, revocar", + "apiKeys.revokeDialog.cancel": "Cancelar", + "apiKeys.noKeysGenerated": "No hay claves generadas", + "apiKeys.copied": "¡Copiado!" +} diff --git a/frontend/src/lib/i18n/messages/es/auth.json b/frontend/src/lib/i18n/messages/es/auth.json new file mode 100644 index 0000000..b300370 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/auth.json @@ -0,0 +1,3 @@ +{ + "auth.brandName": "Wordly" +} diff --git a/frontend/src/lib/i18n/messages/es/checkout.json b/frontend/src/lib/i18n/messages/es/checkout.json new file mode 100644 index 0000000..c23d00d --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/checkout.json @@ -0,0 +1,12 @@ +{ + "checkout.activating": "Activando…", + "checkout.activatingDesc": "Estamos actualizando su suscripción, espere.", + "checkout.paymentConfirmed": "¡Pago confirmado!", + "checkout.subscriptionActivated": "¡Suscripción activada!", + "checkout.planActivated": "¡Plan {plan} activado!", + "checkout.redirectingToProfile": "Redirigiendo a su perfil…", + "checkout.paymentReceived": "Pago recibido", + "checkout.redirecting": "Redirigiendo…", + "checkout.syncError": "Error de sincronización", + "checkout.networkError": "Error de red. Su pago está confirmado — recargue su perfil." +} diff --git a/frontend/src/lib/i18n/messages/es/common.json b/frontend/src/lib/i18n/messages/es/common.json new file mode 100644 index 0000000..ae3dcf0 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/common.json @@ -0,0 +1,4 @@ +{ + "common.loading": "Cargando...", + "common.backToHome": "Volver al inicio" +} diff --git a/frontend/src/lib/i18n/messages/es/context.json b/frontend/src/lib/i18n/messages/es/context.json new file mode 100644 index 0000000..becafeb --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/context.json @@ -0,0 +1,25 @@ +{ + "context.proTitle": "Función Pro", + "context.proDesc": "El contexto y los glosarios profesionales están disponibles con los planes Pro, Business y Enterprise. Proporcionan traducciones más precisas mediante instrucciones y vocabulario específico de tu dominio.", + "context.viewPlans": "Ver planes", + "context.title": "Contexto y glosario", + "context.subtitle": "Mejora la calidad de traducción con instrucciones y vocabulario específico de tu dominio.", + "context.presets.title": "Glosarios profesionales", + "context.presets.desc": "Carga un glosario completo con instrucciones y terminología especializada", + "context.instructions.title": "Instrucciones de contexto", + "context.instructions.desc": "Instrucciones que la IA seguirá durante la traducción", + "context.instructions.placeholder": "P.ej.: Traduces documentos técnicos de climatización. Usa terminología de ingeniería precisa...", + "context.glossary.title": "Glosario técnico", + "context.glossary.desc": "Formato: origen=destino (uno por línea). Los glosarios cargados mediante preset son editables.", + "context.glossary.terms": "términos en el glosario", + "context.clearAll": "Borrar todo", + "context.saving": "Guardando...", + "context.save": "Guardar", + "context.presets.createGlossary": "Crear glosario", + "context.presets.created": "Glosario creado", + "context.presets.createdDesc": "El glosario \\\"{name}\\\" ha sido creado con {count} términos.", + "context.presets.hint": "Haz clic en un preset para crear un glosario con términos específicos del dominio. Gestiona tus glosarios en la sección de Glosarios.", + "context.glossary.manage": "Gestionar glosarios", + "context.saved": "Guardado", + "context.savedDesc": "Tus instrucciones de contexto se han guardado." +} diff --git a/frontend/src/lib/i18n/messages/es/cookieConsent.json b/frontend/src/lib/i18n/messages/es/cookieConsent.json new file mode 100644 index 0000000..e914994 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/cookieConsent.json @@ -0,0 +1,7 @@ +{ + "cookieConsent.title": "Cookies en Wordly", + "cookieConsent.description": "Usamos cookies esenciales para que la aplicación funcione (sesión, seguridad, idioma). Con su permiso, también usamos cookies opcionales para medir el tráfico y mejorar el producto.", + "cookieConsent.acceptAll": "Aceptar todas", + "cookieConsent.essentialOnly": "Solo esenciales", + "cookieConsent.learnMore": "Más información" +} diff --git a/frontend/src/lib/i18n/messages/es/dashboard.json b/frontend/src/lib/i18n/messages/es/dashboard.json new file mode 100644 index 0000000..d267da0 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/dashboard.json @@ -0,0 +1,111 @@ +{ + "dashboard.nav.translate": "Traducir", + "dashboard.nav.profile": "Mi perfil", + "dashboard.nav.settings": "Configuración", + "dashboard.nav.context": "Contexto", + "dashboard.nav.services": "Servicios", + "dashboard.nav.apiKeys": "Claves API", + "dashboard.nav.glossaries": "Glosarios", + "dashboard.header.title": "Panel de control", + "dashboard.header.subtitle": "Gestiona tus traducciones", + "dashboard.header.toggleMenu": "Menú", + "dashboard.header.profileTitle": "Mi perfil", + "dashboard.sidebar.theme": "Tema", + "dashboard.sidebar.signOut": "Cerrar sesión", + "dashboard.sidebar.backHome": "Volver al inicio", + "dashboard.sidebar.upgradeToPro": "Pasar a Pro →", + "dashboard.translate.pageTitle": "Traducir un documento", + "dashboard.translate.pageSubtitle": "Importa un archivo y elige el idioma de destino", + "dashboard.translate.errorNotificationTitle": "Error", + "dashboard.translate.dropzone.uploadAria": "Zona para soltar archivos", + "dashboard.translate.dropzone.title": "Arrastra y suelta tu archivo aquí", + "dashboard.translate.dropzone.subtitle": "o haz clic para seleccionar (DOCX, XLSX, PPTX, PDF)", + "dashboard.translate.dropzone.replaceFile": "Reemplazar archivo", + "dashboard.translate.language.source": "Idioma de origen", + "dashboard.translate.language.target": "Idioma de destino", + "dashboard.translate.language.loading": "Cargando idiomas…", + "dashboard.translate.language.autoDetect": "Detección automática", + "dashboard.translate.language.selectPlaceholder": "Seleccionar…", + "dashboard.translate.language.loadErrorPrefix": "Error al cargar los idiomas", + "dashboard.translate.provider.loading": "Cargando proveedores…", + "dashboard.translate.provider.noneConfigured": "No hay proveedores configurados", + "dashboard.translate.provider.modelTitle": "Modelo", + "dashboard.translate.provider.sectionTitle": "Proveedor", + "dashboard.translate.provider.llmDivider": "IA · Contextual", + "dashboard.translate.provider.llmDividerPro": "IA · Contextual (Pro)", + "dashboard.translate.provider.upgrade": "Mejorar a Pro", + "dashboard.translate.provider.upgradeSuffix": "para desbloquear la traducción IA", + "dashboard.translate.trust.zeroRetention": "Sin retención", + "dashboard.translate.trust.deletedAfter": "Archivos eliminados tras el procesamiento", + "dashboard.translate.actions.uploading": "Subiendo…", + "dashboard.translate.actions.translate": "Traducir", + "dashboard.translate.actions.filePrefix": "Archivo: ", + "dashboard.translate.actions.cancel": "Cancelar", + "dashboard.translate.actions.tryAgain": "Reintentar", + "dashboard.translate.steps.uploading": "Subiendo archivo…", + "dashboard.translate.steps.starting": "Iniciando traducción…", + "dashboard.translate.complete.title": "¡Traducción completada!", + "dashboard.translate.complete.descNamed": "Tu archivo {name} se ha traducido correctamente.", + "dashboard.translate.complete.descGeneric": "Tu archivo se ha traducido correctamente.", + "dashboard.translate.complete.downloading": "Descargando…", + "dashboard.translate.complete.download": "Descargar", + "dashboard.translate.complete.newTranslation": "Nueva traducción", + "dashboard.translate.complete.toastOkTitle": "Éxito", + "dashboard.translate.complete.toastOkDesc": "{name} se ha descargado correctamente.", + "dashboard.translate.complete.toastFailTitle": "Error", + "dashboard.translate.complete.toastFailDesc": "La traducción ha fallado. Por favor, inténtalo de nuevo.", + "dashboard.translate.sourceDocument": "Documento fuente", + "dashboard.translate.configuration": "Configuración", + "dashboard.translate.translating": "Traducción en progreso", + "dashboard.translate.liveMonitor": "Monitor en vivo", + "dashboard.translate.summary": "Resumen", + "dashboard.translate.engine": "Motor", + "dashboard.translate.confidence": "Confianza", + "dashboard.translate.cancel": "Cancelar", + "dashboard.translate.segments": "Segmentos", + "dashboard.translate.characters": "Caracteres", + "dashboard.translate.elapsed": "Transcurrido", + "dashboard.translate.segPerMin": "Seg/min", + "dashboard.translate.highQuality": "Alta calidad", + "dashboard.translate.quality": "Calidad", + "dashboard.translate.completed": "Traducción completada", + "dashboard.translate.replace": "Reemplazar", + "dashboard.translate.pdfMode.title": "Modo de traducción PDF", + "dashboard.translate.pdfMode.preserveLayout": "Conservar diseño", + "dashboard.translate.pdfMode.textOnly": "Solo texto", + "dashboard.translate.pdfMode.preserveLayoutDesc": "Mantiene imágenes, tablas y formato. Ideal para PDFs simples.", + "dashboard.translate.pdfMode.textOnlyDesc": "Traduce todo el texto perfectamente. Salida limpia, sin problemas de diseño.", + "dashboard.translate.pipeline.upload": "Subir", + "dashboard.translate.pipeline.analyze": "Analizar", + "dashboard.translate.pipeline.translate": "Traducción", + "dashboard.translate.pipeline.rebuild": "Reconstruir", + "dashboard.translate.pipeline.finalize": "Finalizar", + "dashboard.translate.progress.processingFallback": "Procesando…", + "dashboard.translate.progress.connectionLost": "Conexión perdida. Reintentando…", + "dashboard.translate.progress.failedTitle": "Traducción fallida", + "dashboard.translate.error.unexpected": "Ocurrió un error inesperado. Inténtelo de nuevo.", + "dashboard.translate.error.noResult": "La traducción no produjo resultados. Verifique que el documento contenga texto e intente de nuevo o elija otro motor.", + "dashboard.translate.error.apiKey": "Clave API no válida o faltante. Contacte al administrador para configurar las claves.", + "dashboard.translate.error.quota": "Límite de uso alcanzado. Intente de nuevo en unos minutos o elija otro motor.", + "dashboard.translate.error.timeout": "La conexión al servicio de traducción expiró. Verifique su red e intente de nuevo.", + "dashboard.translate.error.sessionExpired": "Sesión expirada. Haga clic en Reintentar para reiniciar la traducción.", + "dashboard.translate.error.empty": "El documento parece vacío o no contiene texto traducible (¿PDF escaneado?).", + "dashboard.translate.error.unsupported": "Formato de archivo no compatible o archivo dañado.", + "dashboard.translate.error.connection": "Conexión perdida. Verifique su red e intente de nuevo.", + "dashboard.translate.error.generic": "Traducción fallida: {detail}", + "dashboard.translate.error.title": "Traducción fallida", + "dashboard.translate.retry": "Reintentar traducción", + "dashboard.translate.newFile": "Nuevo archivo", + "dashboard.translate.modeAI": "Modo IA", + "dashboard.translate.modeClassic": "Modo Clásico", + "dashboard.translate.glossaryLLMHint": "Glosarios disponibles en modo IA", + "dashboard.translate.submitting": "Enviando...", + "dashboard.translate.submit": "Iniciar traducción", + "dashboard.translate.noFile": "Suba un archivo primero", + "dashboard.translate.noTargetLang": "Seleccione un idioma de destino", + "dashboard.topbar.interfaceLabel": "Interfaz de traducción", + "dashboard.topbar.premiumAccess": "Acceso Premium", + "dashboard.checkoutSyncError": "Error al sincronizar el pago.", + "dashboard.networkRefresh": "Error de red. Por favor, actualice la página.", + "dashboard.continueToTranslate": "Continuar a la traducción" +} diff --git a/frontend/src/lib/i18n/messages/es/fileUploader.json b/frontend/src/lib/i18n/messages/es/fileUploader.json new file mode 100644 index 0000000..5622375 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/fileUploader.json @@ -0,0 +1,31 @@ +{ + "fileUploader.uploadDocument": "Subir documento", + "fileUploader.uploadDesc": "Arrastre y suelte o haga clic para seleccionar un archivo (Excel, Word, PowerPoint)", + "fileUploader.dropHere": "Suelta tu archivo aquí…", + "fileUploader.dragAndDrop": "Arrastra y suelta tu documento aquí", + "fileUploader.orClickBrowse": "o haz clic para examinar", + "fileUploader.preview": "Vista previa", + "fileUploader.translationOptions": "Opciones de traducción", + "fileUploader.configureSettings": "Configura los ajustes de traducción", + "fileUploader.targetLanguage": "Idioma de destino", + "fileUploader.selectLanguage": "Seleccionar idioma", + "fileUploader.translationProvider": "Proveedor de traducción", + "fileUploader.selectProvider": "Seleccionar proveedor", + "fileUploader.advancedOptions": "Opciones avanzadas", + "fileUploader.translateImages": "Traducir imágenes", + "fileUploader.translating": "Traduciendo…", + "fileUploader.translateDocument": "Traducir documento", + "fileUploader.processing": "Procesando…", + "fileUploader.translationError": "Error de traducción", + "fileUploader.translationComplete": "¡Traducción completa!", + "fileUploader.translationCompleteDesc": "Su documento se ha traducido correctamente conservando todo el formato.", + "fileUploader.download": "Descargar documento traducido", + "fileUploader.webgpuUnsupported": "WebGPU no es compatible con este navegador. Use Chrome 113+ o Edge 113+.", + "fileUploader.webllmNotLoaded": "Modelo WebLLM no cargado. Vaya a Configuración > Servicios de traducción para cargar un modelo.", + "fileUploader.extracting": "Extrayendo textos del documento…", + "fileUploader.noTranslatable": "No se encontró texto traducible en el documento", + "fileUploader.foundTexts": "Se encontraron {count} textos para traducir", + "fileUploader.translatingItem": "Traduciendo {current}/{total}: «{preview}»", + "fileUploader.reconstructing": "Reconstruyendo documento…", + "fileUploader.translatingLocally": "Traduciendo localmente con WebLLM…" +} diff --git a/frontend/src/lib/i18n/messages/es/forgotPassword.json b/frontend/src/lib/i18n/messages/es/forgotPassword.json new file mode 100644 index 0000000..0ac67c8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/forgotPassword.json @@ -0,0 +1,14 @@ +{ + "forgotPassword.enterEmail": "Please enter your email address", + "forgotPassword.error": "An error occurred", + "forgotPassword.title": "Forgot Password", + "forgotPassword.checkEmail": "Check your inbox", + "forgotPassword.subtitle": "Enter your email to receive a reset link", + "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", + "forgotPassword.emailLabel": "Email address", + "forgotPassword.emailPlaceholder": "you@example.com", + "forgotPassword.sending": "Sending...", + "forgotPassword.sendLink": "Send reset link", + "forgotPassword.backToLogin": "Back to login", + "forgotPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/es/glossaries.json b/frontend/src/lib/i18n/messages/es/glossaries.json new file mode 100644 index 0000000..4dad6c4 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/glossaries.json @@ -0,0 +1,189 @@ +{ + "glossaries.yourGlossaries": "Tus glosarios", + "glossaries.title": "Glosarios y Contexto", + "glossaries.description": "Gestiona tus glosarios e instrucciones de contexto para traducciones más precisas.", + "glossaries.createNew": "Crear nuevo", + "glossaries.empty": "Sin glosarios", + "glossaries.emptyDesc": "Crea tu primer glosario o carga un preset profesional arriba", + "glossaries.defineTerms": "términos", + "glossaries.aboutTitle": "Sobre los glosarios", + "glossaries.aboutDesc": "Los glosarios te permiten definir traducciones exactas para términos específicos. Al traducir, los términos del glosario garantizan traducciones consistentes y precisas.", + "glossaries.aboutFormat": "Cada término tiene una palabra fuente y traducciones en varios idiomas. Selecciona un glosario en la página de traducción para aplicarlo.", + "glossaries.toast.created": "Glosario creado", + "glossaries.toast.createdDesc": "El glosario \\\"{name}\\\" ha sido creado.", + "glossaries.toast.imported": "Glosario importado", + "glossaries.toast.importedDesc": "El glosario \\\"{name}\\\" ha sido importado.", + "glossaries.toast.updated": "Glosario actualizado", + "glossaries.toast.updatedDesc": "El glosario \\\"{name}\\\" ha sido actualizado.", + "glossaries.toast.deleted": "Glosario eliminado", + "glossaries.toast.deletedDesc": "El glosario ha sido eliminado.", + "glossaries.toast.error": "Error", + "glossaries.toast.errorCreate": "Error al crear el glosario", + "glossaries.toast.errorImport": "Error al importar el glosario", + "glossaries.toast.errorUpdate": "Error al actualizar el glosario", + "glossaries.toast.errorDelete": "Error al eliminar el glosario", + "glossaries.dialog.title": "Nuevo glosario", + "glossaries.dialog.description": "Crea un glosario para tus traducciones", + "glossaries.dialog.nameLabel": "Nombre", + "glossaries.dialog.namePlaceholder": "Mi glosario", + "glossaries.dialog.tabTemplates": "Plantillas", + "glossaries.dialog.tabFile": "Archivo", + "glossaries.dialog.tabManual": "Manual", + "glossaries.dialog.cancel": "Cancelar", + "glossaries.dialog.creating": "Creando…", + "glossaries.dialog.importing": "Importando…", + "glossaries.dialog.importBtn": "Importar", + "glossaries.dialog.selectPrompt": "Seleccionar", + "glossaries.dialog.createBtn": "Crear", + "glossaries.dialog.createEmpty": "Crear vacío", + "glossaries.dialog.terms": "términos", + "glossaries.dialog.templatesDesc": "Elige una plantilla predefinida", + "glossaries.dialog.templatesEmpty": "No hay plantillas disponibles", + "glossaries.dialog.dropTitle": "Arrastra un archivo CSV aquí", + "glossaries.dialog.dropOr": "o", + "glossaries.dialog.dropFormats": "CSV, TSV, TXT", + "glossaries.termEditor.addTerm": "Añadir término", + "glossaries.termEditor.maxReached": "Se ha alcanzado el máximo de {max} términos por glosario.", + "glossaries.dialog.formatTitle": "Formato", + "glossaries.dialog.formatDesc": "origen,destino (uno por línea)", + "glossaries.dialog.formatNote": "Se ignora la primera línea si se detecta encabezado", + "glossaries.dialog.errorFormat": "Formato no compatible", + "glossaries.dialog.errorSize": "Archivo demasiado grande", + "glossaries.dialog.errorEmpty": "Archivo vacío", + "glossaries.dialog.errorRead": "Error de lectura", + "glossaries.dialog.parsing": "Analizando…", + "glossaries.dialog.termsImported": "términos importados", + "glossaries.dialog.changeFile": "Cambiar archivo", + "glossaries.dialog.retry": "Reintentar", + "glossaries.edit.title": "Modifier le glossaire", + "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", + "glossaries.edit.nameLabel": "Nom du glossaire", + "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", + "glossaries.edit.sourceLang": "Langue source", + "glossaries.edit.targetLang": "Langue cible", + "glossaries.edit.termsLabel": "Termes ({count} valides)", + "glossaries.edit.exportCsv": "Exporter CSV", + "glossaries.edit.importCsv": "Importer CSV", + "glossaries.edit.cancel": "Annuler", + "glossaries.edit.saving": "Enregistrement...", + "glossaries.edit.saveChanges": "Enregistrer les modifications", + "glossaries.edit.importFailedTitle": "Échec de l'importation", + "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", + "glossaries.edit.importSuccessTitle": "Importation réussie", + "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", + "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", + "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", + "glossaries.delete.title": "Supprimer le glossaire", + "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", + "glossaries.delete.warning": "Cette action est irréversible", + "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", + "glossaries.delete.cancel": "Annuler", + "glossaries.delete.deleting": "Suppression...", + "glossaries.delete.deleteBtn": "Supprimer", + "glossaries.upgrade.title": "Glossaires", + "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", + "glossaries.upgrade.feature1": "Créez plusieurs glossaires", + "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", + "glossaries.upgrade.feature3": "Importez/exportez via CSV", + "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", + "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", + "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", + "glossaries.upgrade.proLabel": "Pro", + "glossaries.upgrade.upgradeBtn": "Passer à Pro", + "glossaries.loading": "Chargement...", + "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", + "glossaries.howItWorks.step1Title": "Configurez ici", + "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", + "glossaries.howItWorks.step2Title": "Activez dans Traduire", + "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", + "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", + "glossaries.howItWorks.goToTranslate": "Aller à Traduire", + "glossaries.status.unsaved": "Non enregistré", + "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", + "glossaries.status.inactive": "Inactif", + "glossaries.instructions.whatForBold": "À quoi ça sert ?", + "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", + "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", + "glossaries.instructions.charCount": "{count} caractères", + "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", + "glossaries.instructions.clearAll": "Tout effacer", + "glossaries.instructions.saving": "Enregistrement…", + "glossaries.instructions.saved": "Enregistré", + "glossaries.presets.whatForBold": "À quoi ça sert ?", + "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", + "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", + "glossaries.presets.creating": "Création…", + "glossaries.presets.alreadyImported": "Déjà importé", + "glossaries.presets.it.title": "IT / Logiciel", + "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", + "glossaries.presets.legal.title": "Juridique / Contrats", + "glossaries.presets.legal.desc": "Droit des affaires, contentieux", + "glossaries.presets.medical.title": "Médical / Santé", + "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", + "glossaries.presets.finance.title": "Finance / Comptabilité", + "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", + "glossaries.presets.marketing.title": "Marketing / Publicité", + "glossaries.presets.marketing.desc": "Digital, branding, analytics", + "glossaries.presets.hr.title": "RH / Ressources Humaines", + "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", + "glossaries.presets.scientific.title": "Scientifique / Recherche", + "glossaries.presets.scientific.desc": "Publications, thèses, articles", + "glossaries.presets.ecommerce.title": "E-commerce / Vente", + "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", + "glossaries.grid.title": "Vos", + "glossaries.grid.titleHighlight": "glossaires", + "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", + "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", + "glossaries.grid.activeTranslation": "Traduction active :", + "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", + "glossaries.badge.compatible": "Compatible", + "glossaries.badge.otherTarget": "Autre cible", + "glossaries.card.editTerms": "Modifier les termes", + "glossaries.card.created": "Creado", + "glossaries.card.term": "término", + "glossaries.card.delete": "Supprimer", + "glossaries.grid.searchPlaceholder": "Search a glossary…", + "glossaries.grid.noResults": "No results for this search.", + "glossaries.detail.backToList": "Back to glossaries", + "glossaries.detail.save": "Save", + "glossaries.detail.savedTitle": "Saved", + "glossaries.detail.savedDesc": "The glossary has been updated.", + "glossaries.detail.settingsTitle": "Settings", + "glossaries.detail.sourceLang": "Source language", + "glossaries.detail.targetLang": "Target language", + "glossaries.detail.termsTitle": "Terms", + "glossaries.detail.terms": "terms", + "glossaries.detail.searchTerms": "Filter…", + "glossaries.detail.noTerms": "No terms yet.", + "glossaries.detail.addFirstTerm": "Add the first term", + "glossaries.detail.addTerm": "Add a term", + "glossaries.detail.maxReached": "Maximum limit reached", + "glossaries.detail.source": "Source", + "glossaries.detail.target": "Target", + "glossaries.detail.sourcePlaceholder": "source term", + "glossaries.detail.targetPlaceholder": "target term", + "glossaries.detail.csvTitle": "CSV", + "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", + "glossaries.detail.export": "Export", + "glossaries.detail.import": "Import", + "glossaries.detail.dangerTitle": "Danger zone", + "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", + "glossaries.detail.deleteGlossary": "Delete this glossary", + "glossaries.detail.confirmDelete": "Confirm deletion?", + "glossaries.detail.confirm": "Confirm", + "glossaries.detail.cancel": "Cancel", + "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", + "glossaries.detail.sourceLocked": "fixed", + "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", + "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", + "glossaries.detail.notFoundTitle": "Glossary not found", + "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", + "glossaries.detail.maxTermsTitle": "Limit reached", + "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", + "glossaries.detail.importEmptyTitle": "Empty file", + "glossaries.detail.importEmptyDesc": "No terms detected in this file.", + "glossaries.detail.importedTitle": "Imported", + "glossaries.detail.importedDesc": "{count} terms imported.", + "glossaries.detail.importErrorTitle": "Read error", + "glossaries.detail.importErrorDesc": "Unable to read the file." +} diff --git a/frontend/src/lib/i18n/messages/es/index.ts b/frontend/src/lib/i18n/messages/es/index.ts new file mode 100644 index 0000000..59b9d0b --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/index.ts @@ -0,0 +1,60 @@ +// Auto-generated by scripts/generate_i18n_index.py +// Merges all namespace JSON files for locale "es". + +import admin from "./admin.json"; +import apiKeys from "./apiKeys.json"; +import auth from "./auth.json"; +import checkout from "./checkout.json"; +import common from "./common.json"; +import context from "./context.json"; +import cookieConsent from "./cookieConsent.json"; +import dashboard from "./dashboard.json"; +import fileUploader from "./fileUploader.json"; +import forgotPassword from "./forgotPassword.json"; +import glossaries from "./glossaries.json"; +import landing from "./landing.json"; +import langSelector from "./langSelector.json"; +import layout from "./layout.json"; +import login from "./login.json"; +import memento from "./memento.json"; +import pricing from "./pricing.json"; +import profile from "./profile.json"; +import providerSelector from "./providerSelector.json"; +import providerTheme from "./providerTheme.json"; +import register from "./register.json"; +import resetPassword from "./resetPassword.json"; +import services from "./services.json"; +import settings from "./settings.json"; +import translate from "./translate.json"; +import translateComplete from "./translateComplete.json"; + +const messages: Record = { + ...admin, + ...apiKeys, + ...auth, + ...checkout, + ...common, + ...context, + ...cookieConsent, + ...dashboard, + ...fileUploader, + ...forgotPassword, + ...glossaries, + ...landing, + ...langSelector, + ...layout, + ...login, + ...memento, + ...pricing, + ...profile, + ...providerSelector, + ...providerTheme, + ...register, + ...resetPassword, + ...services, + ...settings, + ...translate, + ...translateComplete, +}; + +export default messages; diff --git a/frontend/src/lib/i18n/messages/es/landing.json b/frontend/src/lib/i18n/messages/es/landing.json new file mode 100644 index 0000000..24a2bd6 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/landing.json @@ -0,0 +1,146 @@ +{ + "landing.nav.why": "¿Por qué nosotros?", + "landing.nav.formats": "Formatos", + "landing.nav.pricing": "Precios", + "landing.nav.login": "Iniciar sesión", + "landing.nav.startFree": "Prueba gratis", + "landing.hero.tag": "IA Documental Profesional", + "landing.hero.titleLine1": "Traduce tus documentos.", + "landing.hero.titleLine2": "Con formato perfecto.", + "landing.hero.description": "El único traductor que preserva SmartArt, gráficos, índices, formas y diseños complejos — exactamente como eran.", + "landing.hero.ctaMain": "Prueba gratis — 2 docs/mes", + "landing.hero.ctaSec": "Ver ofertas", + "landing.hero.deleted": "Archivos eliminados tras 60 min", + "landing.hero.noHidden": "Sin cargos ocultos", + "landing.hero.preview": "Vista previa antes de pagar", + "landing.hero.formattedOk": "Formato OK", + "landing.hero.aiActive": "Traducción IA activa", + "landing.steps.title": "¿Cómo funciona?", + "landing.steps.subtitle": "Tres pasos. Cero pérdida de formato.", + "landing.steps.step1.num": "01", + "landing.steps.step1.title": "Sube tu archivo", + "landing.steps.step1.desc": "Arrastra y suelta tu documento Excel, Word, PowerPoint o PDF.", + "landing.steps.step2.num": "02", + "landing.steps.step2.title": "Elige idioma y motor", + "landing.steps.step2.desc": "Selecciona el idioma destino y el motor — clásico o IA contextual.", + "landing.steps.step3.num": "03", + "landing.steps.step3.title": "Descarga el resultado", + "landing.steps.step3.desc": "Obtén tu documento traducido con un formato idéntico al original.", + "landing.features.tag": "Motor de Traducción IA", + "landing.features.title": "Una traducción que entiende tu oficio", + "landing.features.description": "Nuestros modelos de IA analizan el contexto, respetan tu terminología y hasta traducen el texto dentro de las imágenes.", + "landing.features.context.title": "Contexto sectorial", + "landing.features.context.desc": "Describe tu sector y obtén traducciones adaptadas, no genéricas.", + "landing.features.glossary.title": "Glosarios sectoriales", + "landing.features.glossary.desc": "Define tus términos técnicos. CTA será «Unidad de Tratamiento de Aire», nunca «Llamada a la Acción».", + "landing.features.vision.title": "Visión de imágenes", + "landing.features.vision.desc": "El texto incrustado en imágenes, diagramas y gráficos se detecta y traduce.", + "landing.features.demo.source": "Origen (FR)", + "landing.features.demo.google": "Google Translate", + "landing.features.demo.ours": "Nuestra IA", + "landing.layout.title": "Tu formato,", + "landing.layout.title2": "perfectamente conservado", + "landing.layout.subtitle": "Otros traductores rompen tu diseño. Nosotros no.", + "landing.layout.p1.title": "SmartArt y diagramas", + "landing.layout.p1.desc": "Organigramas, flujos, jerarquías — todo traducido idénticamente.", + "landing.layout.p2.title": "Índices de contenido", + "landing.layout.p2.desc": "Entradas del índice, números de página y referencias cruzadas actualizados correctamente.", + "landing.layout.p3.title": "Gráficos y diagramas", + "landing.layout.p3.desc": "Títulos, etiquetas de ejes, leyendas y nombres de series — todo traducido.", + "landing.layout.p4.title": "Formas y cuadros de texto", + "landing.layout.p4.desc": "Rectángulos, bloques redondeados, llamadas — localizados en todas partes.", + "landing.layout.p5.title": "Encabezados y pies de página", + "landing.layout.p5.desc": "Encabezados, pies de página y notas al pie nunca se pasan por alto.", + "landing.layout.p6.title": "130+ idiomas", + "landing.layout.p6.desc": "Google Translate, DeepL y motores de IA de grado profesional.", + "landing.formats.title": "Cada formato,", + "landing.formats.title2": "cada elemento", + "landing.formats.subtitle": "Traducimos lo que otros olvidan. Tu empresa merece una documentación impecable.", + "landing.formats.word.name": "Word", + "landing.formats.word.i1": "Párrafos y encabezados", + "landing.formats.word.i2": "Tablas y gráficos", + "landing.formats.word.i3": "Diagramas SmartArt", + "landing.formats.word.i4": "Índice de contenido", + "landing.formats.word.i5": "Encabezados y pies", + "landing.formats.word.i6": "Formas y cuadros de texto", + "landing.formats.word.i7": "Notas al pie y al final", + "landing.formats.excel.name": "Excel", + "landing.formats.excel.i1": "Valores de celdas", + "landing.formats.excel.i2": "Nombres de hojas", + "landing.formats.excel.i3": "Gráficos y etiquetas", + "landing.formats.excel.i4": "Encabezados y pies", + "landing.formats.excel.i5": "Celdas combinadas conservadas", + "landing.formats.pptx.name": "PowerPoint", + "landing.formats.pptx.i1": "Texto de diapositivas y notas", + "landing.formats.pptx.i2": "Gráficos y diagramas", + "landing.formats.pptx.i3": "Formas y cuadros de texto", + "landing.formats.pptx.i4": "Diseños maestros", + "landing.formats.pptx.i5": "Animaciones conservadas", + "landing.formats.pdf.name": "PDF", + "landing.formats.pdf.i1": "PDF basados en texto", + "landing.formats.pdf.i2": "Diseño conservado", + "landing.formats.pdf.i3": "Imágenes en su lugar", + "landing.formats.pdf.i4": "Tablas mantenidas", + "landing.formats.pdf.i5": "Salida como DOCX o PDF", + "landing.pricing.title": "Precios simples y honestos", + "landing.pricing.subtitle": "Lo que ves es lo que pagas. Sin cargos ocultos.", + "landing.pricing.monthly": "Mensual", + "landing.pricing.annual": "Anual", + "landing.pricing.bestValue": "Más popular", + "landing.pricing.month": "/mes", + "landing.pricing.footer": "El precio mostrado es el precio que pagas. Sin cargos ocultos después de la traducción.", + "landing.pricing.starter.name": "Starter", + "landing.pricing.starter.desc": "Para particulares y proyectos pequeños", + "landing.pricing.starter.f1": "50 documentos / mes", + "landing.pricing.starter.f2": "Hasta 50 páginas por doc", + "landing.pricing.starter.f3": "Google Translate + DeepL", + "landing.pricing.starter.f4": "Archivos de hasta 10 MB", + "landing.pricing.starter.cta": "Empezar", + "landing.pricing.pro.name": "Pro", + "landing.pricing.pro.desc": "Para profesionales exigentes", + "landing.pricing.pro.f1": "200 documentos / mes", + "landing.pricing.pro.f2": "Hasta 200 páginas por doc", + "landing.pricing.pro.f3": "Traducción con IA", + "landing.pricing.pro.f4": "Google + DeepL incluidos", + "landing.pricing.pro.f5": "Glosarios y prompts personalizados", + "landing.pricing.pro.f6": "Soporte prioritario", + "landing.pricing.pro.cta": "Probar Pro", + "landing.pricing.business.name": "Business", + "landing.pricing.business.desc": "Para equipos con grandes necesidades", + "landing.pricing.business.f1": "1 000 documentos / mes", + "landing.pricing.business.f2": "Hasta 500 páginas por doc", + "landing.pricing.business.f3": "IA Premium (Claude)", + "landing.pricing.business.f4": "Todos los proveedores + API", + "landing.pricing.business.f5": "Webhooks y automatización", + "landing.pricing.business.f6": "5 puestos de equipo", + "landing.pricing.business.cta": "Contáctenos", + "landing.cta.title": "Empieza a traducir en 30 segundos", + "landing.cta.subtitle": "No se necesita tarjeta de crédito. Prueba gratis ahora y da vida a tus documentos multilingües.", + "landing.cta.button": "Crear cuenta gratuita", + "landing.cta.secure": "Protegido con cifrado AES-256", + "landing.footer.desc": "Especialistas en traducción inteligente de documentos. Combinamos el arte del diseño con la ciencia de la IA contextual.", + "landing.footer.product": "Producto", + "landing.footer.resources": "Recursos", + "landing.footer.legal": "Legal", + "landing.footer.rights": "© 2026 Wordly.art — Todos los derechos reservados.", + "landing.hero.contextEngine": "Traducción detectada: Término técnico de mantenimiento para sistemas HVAC...", + "landing.hero.liveAnalysis": "Análisis en vivo", + "landing.hero.termsDetected": "términos detectados", + "landing.steps.process": "PROCESO", + "landing.translate.newProject": "Nuevo proyecto", + "landing.translate.title": "Traducir un documento", + "landing.translate.subtitle": "Importa un archivo y elige el idioma de destino", + "landing.translate.sourceDocument": "Documento fuente", + "landing.translate.configuration": "Configuración", + "landing.translate.sourceLang": "Idioma de origen", + "landing.translate.targetLang": "Idioma de destino", + "landing.translate.provider": "Proveedor", + "landing.translate.startTranslation": "Iniciar traducción", + "landing.translate.zeroRetention": "Retención cero", + "landing.translate.filesDeleted": "Archivos eliminados tras el procesamiento", + "landing.translate.dropHere": "Arrastra y suelta aquí", + "landing.translate.supportedFormats": "Archivos DOCX, XLSX, PPTX o PDF compatibles", + "landing.translate.aiAnalysis": "Análisis IA Activo", + "landing.translate.processing": "Procesando", + "landing.translate.preservingLayout": "Tu diseño se está preservando" +} diff --git a/frontend/src/lib/i18n/messages/es/langSelector.json b/frontend/src/lib/i18n/messages/es/langSelector.json new file mode 100644 index 0000000..21ae600 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/langSelector.json @@ -0,0 +1,7 @@ +{ + "langSelector.search": "Buscar…", + "langSelector.noResults": "Sin resultados", + "langSelector.source": "Origen", + "langSelector.target": "Destino", + "langSelector.swap": "Intercambiar" +} diff --git a/frontend/src/lib/i18n/messages/es/layout.json b/frontend/src/lib/i18n/messages/es/layout.json new file mode 100644 index 0000000..57849c9 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/layout.json @@ -0,0 +1,5 @@ +{ + "layout.nav.apiAccess": "Acceso API", + "layout.footer.terms": "Términos", + "layout.footer.privacy": "Privacidad" +} diff --git a/frontend/src/lib/i18n/messages/es/login.json b/frontend/src/lib/i18n/messages/es/login.json new file mode 100644 index 0000000..2e75c0e --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/login.json @@ -0,0 +1,18 @@ +{ + "login.errorTitle": "Login Error", + "login.welcomeBack": "Welcome back", + "login.signInToContinue": "Sign in to continue translating", + "login.email": "Email", + "login.emailPlaceholder": "you@example.com", + "login.password": "Password", + "login.forgotPassword": "Forgot password?", + "login.passwordPlaceholder": "••••••••", + "login.signingIn": "Signing in...", + "login.signIn": "Sign In", + "login.noAccount": "Don't have an account?", + "login.signUpFree": "Sign up for free", + "login.orContinueWith": "o continuar con correo electrónico", + "login.google.connecting": "Conectando…", + "login.google.errorGeneric": "Se ha producido un error con el inicio de sesión de Google.", + "login.google.errorFailed": "Error al iniciar sesión con Google. Inténtalo de nuevo." +} diff --git a/frontend/src/lib/i18n/messages/es/memento.json b/frontend/src/lib/i18n/messages/es/memento.json new file mode 100644 index 0000000..ee87679 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/memento.json @@ -0,0 +1,6 @@ +{ + "memento.title": "Descubre Momento", + "memento.slogan": "Momento no es solo una aplicación de notas. Es un ecosistema inteligente que conecta, analiza y desarrolla tus ideas en tiempo real usando 6 agentes de IA y búsqueda semántica avanzada.", + "memento.ctaFree": "Empezar gratis", + "memento.ctaMore": "Saber más" +} diff --git a/frontend/src/lib/i18n/messages/es/pricing.json b/frontend/src/lib/i18n/messages/es/pricing.json new file mode 100644 index 0000000..d095d27 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/pricing.json @@ -0,0 +1,151 @@ +{ + "pricing.nav.back": "Volver", + "pricing.nav.home": "Inicio", + "pricing.nav.mySubscription": "Mi suscripción", + "pricing.header.badge": "Modelos IA actualizados — Marzo 2026", + "pricing.header.title": "Un plan para cada necesidad", + "pricing.header.subtitle": "Traduce tus documentos de Word, Excel y PowerPoint conservando el diseño original. Sin necesidad de clave API.", + "pricing.billing.monthly": "Mensual", + "pricing.billing.yearly": "Anual", + "pricing.plans.free.name": "Gratis", + "pricing.plans.starter.name": "Starter", + "pricing.plans.pro.name": "Pro", + "pricing.plans.business.name": "Business", + "pricing.plans.enterprise.name": "Enterprise", + "pricing.plans.free.description": "Perfecto para descubrir la aplicación", + "pricing.plans.starter.description": "Para particulares y proyectos pequeños", + "pricing.plans.pro.description": "Para profesionales y equipos en crecimiento", + "pricing.plans.business.description": "Para equipos y organizaciones", + "pricing.plans.enterprise.description": "Soluciones a medida para grandes organizaciones", + "pricing.plans.pro.highlight": "El más popular", + "pricing.plans.pro.badge": "POPULAR", + "pricing.plans.enterprise.badge": "BAJO PETICIÓN", + "pricing.plans.free.feat1": "5 documentos / mes", + "pricing.plans.free.feat2": "Hasta 15 páginas por documento", + "pricing.plans.free.feat3": "Traductor de Google incluido", + "pricing.plans.free.feat4": "Todos los idiomas (130+)", + "pricing.plans.free.feat5": "Soporte comunitario", + "pricing.plans.starter.feat1": "50 documentos / mes", + "pricing.plans.starter.feat2": "Hasta 50 páginas por documento", + "pricing.plans.starter.feat3": "Traductor de Google + DeepL", + "pricing.plans.starter.feat4": "Archivos de hasta 10 MB", + "pricing.plans.starter.feat5": "Soporte por correo electrónico", + "pricing.plans.starter.feat6": "Historial de 30 días", + "pricing.plans.pro.feat1": "200 documentos / mes", + "pricing.plans.pro.feat2": "Hasta 200 páginas por documento", + "pricing.plans.pro.feat3": "Traducción IA Esencial", + "pricing.plans.pro.feat4": "Traductor de Google + DeepL", + "pricing.plans.pro.feat5": "Archivos de hasta 25 MB", + "pricing.plans.pro.feat6": "Glosarios personalizados", + "pricing.plans.pro.feat7": "Soporte prioritario", + "pricing.plans.pro.feat8": "Historial de 90 días", + "pricing.plans.business.feat1": "1 000 documentos / mes", + "pricing.plans.business.feat2": "Hasta 500 páginas por documento", + "pricing.plans.business.feat3": "IA Esencial + Premium (Claude Haiku)", + "pricing.plans.business.feat4": "Todos los proveedores de traducción", + "pricing.plans.business.feat5": "Archivos de hasta 50 MB", + "pricing.plans.business.feat6": "Acceso API (10 000 llamadas/mes)", + "pricing.plans.business.feat7": "Webhooks de notificación", + "pricing.plans.business.feat8": "Soporte dedicado", + "pricing.plans.business.feat9": "Historial de 1 año", + "pricing.plans.business.feat10": "Analíticas avanzadas", + "pricing.plans.enterprise.feat1": "Documentos ilimitados", + "pricing.plans.enterprise.feat2": "Todos los modelos de IA (GPT-5, Claude Opus 4.6…)", + "pricing.plans.enterprise.feat3": "Implementación local o en nube dedicada", + "pricing.plans.enterprise.feat4": "SLA 99,9 % garantizado", + "pricing.plans.enterprise.feat5": "Soporte dedicado 24/7", + "pricing.plans.enterprise.feat6": "Marca blanca", + "pricing.plans.enterprise.feat7": "Equipos ilimitados", + "pricing.plans.enterprise.feat8": "Integraciones a medida", + "pricing.card.onRequest": "Bajo petición", + "pricing.card.free": "Gratis", + "pricing.card.perMonth": "/mes", + "pricing.card.billedYearly": "Facturado {price} € / año", + "pricing.card.documents": "Documentos", + "pricing.card.pagesMax": "Páginas máx.", + "pricing.card.aiTranslation": "Traducción IA", + "pricing.card.unlimited": "Ilimitado", + "pricing.card.perMonthStat": "/ mes", + "pricing.card.perDoc": "p / doc", + "pricing.card.aiEssential": "Esencial", + "pricing.card.aiEssentialPremium": "Esencial + Premium", + "pricing.card.aiCustom": "A medida", + "pricing.card.myPlan": "Mi plan", + "pricing.card.managePlan": "Gestionar mi plan", + "pricing.card.startFree": "Empezar gratis", + "pricing.card.contactUs": "Contáctenos", + "pricing.card.choosePlan": "Elegir este plan", + "pricing.card.processing": "Procesando…", + "pricing.comparison.title": "Comparación detallada", + "pricing.comparison.subtitle": "Todo lo incluido en cada plan", + "pricing.comparison.feature": "Característica", + "pricing.comparison.docsPerMonth": "Documentos / mes", + "pricing.comparison.pagesMaxPerDoc": "Páginas máx. / documento", + "pricing.comparison.maxFileSize": "Tamaño máx. de archivo", + "pricing.comparison.googleTranslation": "Traductor de Google", + "pricing.comparison.deepl": "DeepL", + "pricing.comparison.aiEssential": "Traducción IA Esencial", + "pricing.comparison.aiPremium": "Traducción IA Premium", + "pricing.comparison.apiAccess": "Acceso API", + "pricing.comparison.priorityProcessing": "Procesamiento prioritario", + "pricing.comparison.support": "Soporte", + "pricing.comparison.support.community": "Comunidad", + "pricing.comparison.support.email": "Correo electrónico", + "pricing.comparison.support.priority": "Prioritario", + "pricing.comparison.support.dedicated": "Dedicado", + "pricing.comparison.mb": "MB", + "pricing.credits.title": "Créditos adicionales", + "pricing.credits.subtitle": "¿Necesitas más? Compra créditos individuales, sin suscripción.", + "pricing.credits.perPage": "1 crédito = 1 página traducida.", + "pricing.credits.bestValue": "Mejor relación calidad-precio", + "pricing.credits.unit": "créditos", + "pricing.credits.centsPerCredit": "cts / crédito", + "pricing.credits.buy": "Comprar", + "pricing.trust.encryption.title": "Cifrado de extremo a extremo", + "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 en reposo", + "pricing.trust.languages.title": "130+ idiomas", + "pricing.trust.languages.sub": "Incluido árabe, persa, hebreo (RTL)", + "pricing.trust.parallel.title": "Procesamiento en paralelo", + "pricing.trust.parallel.sub": "IA multiproceso ultrarrápida", + "pricing.trust.availability.title": "Disponible 24/7", + "pricing.trust.availability.sub": "Disponibilidad garantizada del 99,9 %", + "pricing.aiModels.title": "Nuestros modelos de IA — Marzo 2026", + "pricing.aiModels.essential.title": "Traducción IA Esencial", + "pricing.aiModels.essential.plan": "Plan Pro", + "pricing.aiModels.essential.descPrefix": "Basado en", + "pricing.aiModels.essential.descSuffix": "— el modelo de IA más rentable de 2026. Calidad comparable a los modelos frontier a una fracción del coste.", + "pricing.aiModels.essential.modelName": "nuestro modelo IA Esencial", + "pricing.aiModels.essential.context": "163K tokens de contexto", + "pricing.aiModels.essential.value": "Excelente relación calidad-precio", + "pricing.aiModels.premium.title": "Traducción IA Premium", + "pricing.aiModels.premium.plan": "Plan Business", + "pricing.aiModels.premium.descPrefix": "Basado en", + "pricing.aiModels.premium.descSuffix": "de Anthropic — preciso en documentos jurídicos, médicos y técnicos complejos.", + "pricing.aiModels.premium.context": "200K tokens de contexto", + "pricing.aiModels.premium.precision": "Máxima precisión", + "pricing.faq.title": "Preguntas frecuentes", + "pricing.faq.q1": "¿Puedo cambiar de plan en cualquier momento?", + "pricing.faq.a1": "Sí. La mejora es inmediata y prorrateada. La bajada se aplica al final del periodo actual.", + "pricing.faq.q2": "¿Qué es la «Traducción IA Esencial»?", + "pricing.faq.a2": "Es nuestro motor de IA. Comprende el contexto de tus documentos, conserva el diseño y maneja términos técnicos mucho mejor que una traducción clásica.", + "pricing.faq.q3": "¿Cuál es la diferencia entre IA Esencial e IA Premium?", + "pricing.faq.a3": "La IA Esencial usa un modelo optimizado (excelente relación calidad-precio). La IA Premium usa Claude 3.5 Haiku de Anthropic, más precisa en documentos jurídicos, médicos y técnicos complejos.", + "pricing.faq.q4": "¿Se conservan mis documentos después de la traducción?", + "pricing.faq.a4": "Los archivos traducidos están disponibles según tu plan (30 días Starter, 90 días Pro, 1 año Business). Están cifrados en reposo y en tránsito.", + "pricing.faq.q5": "¿Qué ocurre si supero mi cuota mensual?", + "pricing.faq.a5": "Puedes comprar créditos adicionales de forma individual o mejorar tu plan. Se te notificará al alcanzar el 80 % de uso.", + "pricing.faq.q6": "¿Hay una prueba gratuita para los planes de pago?", + "pricing.faq.a6": "El plan Gratuito es permanente y no requiere tarjeta. Para los planes Pro y Business, contáctenos para una prueba de 14 días.", + "pricing.faq.q7": "¿Qué formatos de archivo son compatibles?", + "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx) y próximamente PDF. Todos los planes son compatibles con los mismos formatos.", + "pricing.cta.title": "¿Listo para empezar?", + "pricing.cta.subtitle": "Empieza gratis, sin tarjeta de crédito. Mejora tu plan cuando lo necesites.", + "pricing.cta.createAccount": "Crear una cuenta gratuita", + "pricing.cta.login": "Iniciar sesión", + "pricing.toast.demo": "Modo demo — Stripe aún no está configurado. En producción, serías redirigido al pago para activar el plan {planId}.", + "pricing.toast.networkError": "Error de red. Por favor, inténtalo de nuevo.", + "pricing.toast.paymentError": "Error al crear el pago.", + "pricing.dashboard": "Panel", + "pricing.okSymbol": "✓", + "pricing.errSymbol": "✕" +} diff --git a/frontend/src/lib/i18n/messages/es/profile.json b/frontend/src/lib/i18n/messages/es/profile.json new file mode 100644 index 0000000..9e19f06 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/profile.json @@ -0,0 +1,58 @@ +{ + "profile.header.title": "Mi perfil", + "profile.header.subtitle": "Gestiona tu cuenta y preferencias.", + "profile.tabs.account": "Cuenta", + "profile.tabs.subscription": "Suscripción", + "profile.tabs.preferences": "Preferencias", + "profile.account.user": "Usuario", + "profile.account.memberSince": "Miembro desde", + "profile.plan.label": "Plan", + "profile.plan.free": "Gratis", + "profile.plan.starter": "Starter", + "profile.plan.pro": "Pro", + "profile.plan.business": "Business", + "profile.plan.enterprise": "Enterprise", + "profile.plan.pricePerMonth": "{price} €/mes", + "profile.subscription.canceling": "Cancelando", + "profile.subscription.active": "Activa", + "profile.subscription.unknown": "Desconocido", + "profile.subscription.accessUntil": "Acceso hasta", + "profile.subscription.renewalOn": "Renovación el", + "profile.subscription.upgradePlan": "Mejorar a un plan de pago", + "profile.subscription.changePlan": "Cambiar plan", + "profile.subscription.manageBilling": "Gestionar facturación", + "profile.subscription.billingUnavailable": "Portal de facturación no disponible.", + "profile.subscription.billingError": "Error al acceder al portal de facturación.", + "profile.subscription.cancelSuccess": "Suscripción cancelada. Mantienes el acceso hasta el final del periodo.", + "profile.subscription.cancelError": "Error durante la cancelación.", + "profile.subscription.networkError": "Error de red.", + "profile.usage.title": "Uso este mes", + "profile.usage.resetOn": "Reinicio el", + "profile.usage.documents": "Documentos", + "profile.usage.pages": "Páginas", + "profile.usage.extraCredits": "crédito extra", + "profile.usage.extraCreditsPlural": "créditos extra", + "profile.usage.quotaReached": "Cuota alcanzada", + "profile.usage.quotaReachedDesc": "Mejora a un plan superior para continuar.", + "profile.usage.unlockMore": "Desbloquea más traducciones con un plan de pago.", + "profile.usage.viewPlans": "Ver planes", + "profile.usage.includedInPlan": "Incluido en tu plan", + "profile.danger.title": "Zona de peligro", + "profile.danger.description": "La cancelación surte efecto al final de tu periodo actual. Mantienes el acceso hasta esa fecha.", + "profile.danger.confirm": "¿Estás seguro? Esta acción no se puede deshacer.", + "profile.danger.confirmCancel": "Confirmar cancelación", + "profile.danger.cancelSubscription": "Cancelar mi suscripción", + "profile.danger.keep": "No, mantener", + "profile.prefs.interfaceLang": "Idioma de la interfaz", + "profile.prefs.interfaceLangDesc": "El idioma se detecta automáticamente según tu navegador. Puedes cambiarlo manualmente.", + "profile.prefs.defaultTargetLang": "Idioma de destino predeterminado", + "profile.prefs.selectLanguage": "Seleccionar un idioma", + "profile.prefs.defaultTargetLangDesc": "Este idioma se preseleccionará para tus traducciones.", + "profile.prefs.save": "Guardar", + "profile.prefs.theme": "Tema", + "profile.prefs.themeDesc": "Elige la apariencia de la interfaz", + "profile.prefs.cache": "Caché", + "profile.prefs.cacheDesc": "Borrar la caché local puede solucionar algunos problemas de visualización.", + "profile.prefs.clearing": "Borrando...", + "profile.prefs.clearCache": "Borrar caché" +} diff --git a/frontend/src/lib/i18n/messages/es/providerSelector.json b/frontend/src/lib/i18n/messages/es/providerSelector.json new file mode 100644 index 0000000..c86a7a7 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/providerSelector.json @@ -0,0 +1,7 @@ +{ + "providerSelector.noClassic": "No hay traductor estándar disponible.", + "providerSelector.noLlm": "Ningún modelo de IA configurado.", + "providerSelector.costOne": "Costo: 1 crédito por página", + "providerSelector.costFive": "Costo: 5 créditos por página (Factor Premium)", + "providerSelector.unlockContextual": "Desbloquee la traducción contextual premium para sus documentos completos." +} diff --git a/frontend/src/lib/i18n/messages/es/providerTheme.json b/frontend/src/lib/i18n/messages/es/providerTheme.json new file mode 100644 index 0000000..9ce5bc3 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/providerTheme.json @@ -0,0 +1,29 @@ +{ + "providerTheme.deepseek.badge": "Esencial", + "providerTheme.deepseek.subBadge": "Técnico y económico", + "providerTheme.deepseek.desc": "Traducción ultraprecisa y económica, ideal para documentos técnicos y código.", + "providerTheme.openai.badge": "Premium", + "providerTheme.openai.subBadge": "Alta fidelidad", + "providerTheme.openai.desc": "El estándar global de IA. Máxima coherencia textual y respeto estricto del estilo.", + "providerTheme.minimax.badge": "Avanzada", + "providerTheme.minimax.subBadge": "Rendimiento", + "providerTheme.minimax.desc": "Velocidad de ejecución increíble y excelente comprensión de estructuras complejas.", + "providerTheme.openrouter.badge": "Exprés", + "providerTheme.openrouter.subBadge": "Multi-modelo", + "providerTheme.openrouter.desc": "Acceso unificado a los mejores modelos de código abierto optimizados para traducción.", + "providerTheme.openrouter_premium.badge": "Ultra", + "providerTheme.openrouter_premium.subBadge": "Contexto máximo", + "providerTheme.openrouter_premium.desc": "Asistido por modelos de última generación (GPT-4o, Claude Sonnet 4.6) para documentos largos.", + "providerTheme.zai.badge": "Especializada", + "providerTheme.zai.subBadge": "Finanzas y Derecho", + "providerTheme.zai.desc": "Modelo ajustado para terminologías empresariales exigentes (legal, finanzas).", + "providerTheme.default.badge": "Moderno", + "providerTheme.default.subBadge": "Razonamiento IA", + "providerTheme.default.desc": "Traducción por modelo de lenguaje grande (LLM) con análisis semántico avanzado.", + "providerTheme.classic.google.label": "Google Traductor", + "providerTheme.classic.google.desc": "Traducción ultrarrápida que cubre más de 130 idiomas. Recomendado para flujos generales.", + "providerTheme.classic.deepl.label": "DeepL Pro", + "providerTheme.classic.deepl.desc": "Traducción de alta precisión conocida por su fluidez y formulaciones naturales.", + "providerTheme.classic.google_cloud.label": "Google Cloud API", + "providerTheme.classic.google_cloud.desc": "Motor en la nube profesional optimizado para procesar grandes volúmenes de documentos." +} diff --git a/frontend/src/lib/i18n/messages/es/register.json b/frontend/src/lib/i18n/messages/es/register.json new file mode 100644 index 0000000..7acfc40 --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/register.json @@ -0,0 +1,29 @@ +{ + "register.title": "Crear una cuenta", + "register.subtitle": "Empieza a traducir gratis", + "register.error.failed": "Error en el registro", + "register.name.label": "Nombre", + "register.name.placeholder": "Tu nombre", + "register.name.error": "El nombre debe tener al menos 2 caracteres", + "register.email.label": "Correo electrónico", + "register.email.placeholder": "tu@ejemplo.com", + "register.email.error": "Dirección de correo no válida", + "register.password.label": "Contraseña", + "register.password.error": "La contraseña debe tener al menos 8 caracteres, una mayúscula, una minúscula y un dígito", + "register.password.show": "Mostrar contraseña", + "register.password.hide": "Ocultar contraseña", + "register.password.strengthLabel": "Fortaleza:", + "register.password.strength.weak": "Débil", + "register.password.strength.medium": "Media", + "register.password.strength.strong": "Fuerte", + "register.confirmPassword.label": "Confirmar contraseña", + "register.confirmPassword.error": "Las contraseñas no coinciden", + "register.confirmPassword.show": "Mostrar", + "register.confirmPassword.hide": "Ocultar", + "register.submit.creating": "Creando cuenta...", + "register.submit.create": "Crear mi cuenta", + "register.hasAccount": "¿Ya tienes una cuenta?", + "register.login": "Iniciar sesión", + "register.terms.prefix": "Al crear una cuenta, aceptas nuestros", + "register.terms.link": "términos de servicio" +} diff --git a/frontend/src/lib/i18n/messages/es/resetPassword.json b/frontend/src/lib/i18n/messages/es/resetPassword.json new file mode 100644 index 0000000..680714f --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/resetPassword.json @@ -0,0 +1,22 @@ +{ + "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", + "resetPassword.passwordMismatch": "Passwords do not match", + "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", + "resetPassword.error": "An error occurred", + "resetPassword.invalidLink": "Invalid link", + "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", + "resetPassword.requestNewLink": "Request new link", + "resetPassword.successTitle": "Password reset", + "resetPassword.newPasswordTitle": "New password", + "resetPassword.successSubtitle": "You will be redirected to login", + "resetPassword.subtitle": "Set your new password", + "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", + "resetPassword.newPassword": "New password", + "resetPassword.showPassword": "Show password", + "resetPassword.hidePassword": "Hide password", + "resetPassword.confirmPassword": "Confirm password", + "resetPassword.resetting": "Resetting...", + "resetPassword.resetPassword": "Reset password", + "resetPassword.backToLogin": "Back to login", + "resetPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/es/services.json b/frontend/src/lib/i18n/messages/es/services.json new file mode 100644 index 0000000..6fa3bed --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/services.json @@ -0,0 +1,14 @@ +{ + "services.title": "Proveedores de traducción", + "services.subtitle": "Los proveedores están configurados por el administrador. Puedes ver cuáles están disponibles para tu cuenta.", + "services.loading": "Cargando proveedores...", + "services.noProviders": "No hay proveedores configurados actualmente. Contacta a tu administrador.", + "services.classic": "Traducción clásica", + "services.llmPro": "LLM · Contextual (Pro)", + "services.available": "Disponible", + "services.model": "Modelo", + "services.adminOnly.title": "La configuración de proveedores es solo para administradores", + "services.adminOnly.desc": "Las claves API, la selección de modelos y la activación de proveedores son gestionadas exclusivamente por el administrador en el panel de administración. Nunca necesitas introducir una clave API.", + "services.fallback.google.label": "Google Traductor", + "services.fallback.google.desc": "Traducción rápida, más de 130 idiomas" +} diff --git a/frontend/src/lib/i18n/messages/es/settings.json b/frontend/src/lib/i18n/messages/es/settings.json new file mode 100644 index 0000000..b08681d --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/settings.json @@ -0,0 +1,20 @@ +{ + "settings.title": "Configuración", + "settings.subtitle": "Configuración general de la aplicación", + "settings.formats.title": "Formatos compatibles", + "settings.formats.subtitle": "Tipos de documentos que puedes traducir", + "settings.formats.formulas": "Fórmulas", + "settings.formats.styles": "Estilos", + "settings.formats.images": "Imágenes", + "settings.formats.headers": "Encabezados", + "settings.formats.tables": "Tablas", + "settings.formats.slides": "Diapositivas", + "settings.formats.notes": "Notas", + "settings.cache.title": "Caché", + "settings.cache.desc": "Borrar la caché local puede solucionar algunos problemas de visualización.", + "settings.cache.clearing": "Borrando...", + "settings.cache.clear": "Borrar caché", + "settings.formats.excel.name": "Excel", + "settings.formats.word.name": "Word", + "settings.formats.powerpoint.name": "PowerPoint" +} diff --git a/frontend/src/lib/i18n/messages/es/translate.json b/frontend/src/lib/i18n/messages/es/translate.json new file mode 100644 index 0000000..4b4b0be --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/translate.json @@ -0,0 +1,92 @@ +{ + "translate.mode.label": "Mode de traduction", + "translate.mode.classic": "Classique", + "translate.mode.classicDesc": "Rapide", + "translate.mode.proLlm": "Pro LLM", + "translate.mode.proLlmDesc": "Contextuel", + "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", + "translate.mode.upgradeLink": "Passer à Pro", + "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", + "translate.glossary.title": "Glosario", + "translate.glossary.select": "Seleccionar glosario", + "translate.glossary.none": "Ninguno", + "translate.glossary.terms": "términos", + "translate.glossary.proOnly": "Actualiza a Pro para usar glosarios", + "translate.glossary.myGlossaries": "Mis glosarios", + "translate.glossary.fromTemplate": "Crear desde plantilla", + "translate.glossary.noGlossaryForPair": "Sin glosario para", + "translate.glossary.noGlossaries": "Sin glosarios", + "translate.glossary.loading": "Cargando...", + "translate.glossary.classicMode": "Motor neutro sin glosario (solo IA)", + "translate.glossary.selectPlaceholder": "Seleccionar un glosario...", + "translate.glossary.multilingual": "MULTILINGÜE", + "translate.glossary.noGlossaryAvailable": "Ningún glosario disponible", + "translate.glossary.filterByLang": "Filtrar por idioma", + "translate.glossary.active": "Activo", + "translate.glossary.inactive": "Inactivo", + "translate.glossary.availableTemplates": "Plantillas disponibles", + "translate.glossary.importing": "Importando...", + "translate.glossary.imported": "(Importado)", + "translate.glossary.noGlossaryForSource": "Ningún glosario ni plantilla para el idioma de origen", + "translate.glossary.createGlossary": "Crear un glosario", + "translate.glossary.showAll": "Mostrar todos los glosarios", + "translate.glossary.activePreview": "Vista previa de correspondencias activas:", + "translate.glossary.total": "en total", + "translate.glossary.moreTerms": "términos más", + "translate.glossary.noTerms": "Ningún término en este glosario.", + "translate.glossary.sourceTerm": "Término fuente", + "translate.glossary.translation": "Traducción", + "translate.glossary.addTerm": "Añadir término", + "translate.glossary.disabledMode": "Motor neutro sin glosario aplicado", + "translate.glossary.addTermError": "Error al añadir el término", + "translate.glossary.networkError": "Error de red", + "translate.glossary.importFailed": "Error al importar ({status})", + "translate.glossary.helpText": "El glosario fuerza la traducción de términos precisos. Elija un glosario cuyo idioma de origen coincida con el idioma original de su documento.", + "translate.glossary.sourceWarning": "Atención: Este glosario usa el idioma de origen", + "translate.glossary.sourceWarningBut": "pero su documento está configurado en", + "translate.glossary.targetWarning": "Incompatibilidad de destino: Este glosario está diseñado para traducir a", + "translate.glossary.targetWarningBut": "pero su documento tiene como destino", + "translate.glossary.targetWarningEnd": "Los términos pueden no ser relevantes.", + "translate.header.processing": "Procesamiento en curso", + "translate.header.aiActive": "Análisis IA activo", + "translate.header.aiActiveDesc": "Su diseño se está preservando por nuestro motor contextual.", + "translate.header.completed": "Completado", + "translate.header.completedTitle": "Traducción completada", + "translate.header.proSpace": "Espacio Pro", + "translate.header.translateDoc": "Traducir un documento", + "translate.header.translateDocDesc": "Conserve el diseño original con nuestro motor de traducción de ultra alta fidelidad.", + "translate.upload.nativeFormat": "Formato nativo", + "translate.fileType.word": "Word (.docx)", + "translate.fileType.excel": "Excel (.xlsx)", + "translate.fileType.slides": "Diapositivas (.pptx)", + "translate.fileType.pdf": "PDF (.pdf)", + "translate.startTranslation": "Iniciar traducción", + "translate.submit": "Enviando…", + "translate.chooseTargetLang": "Por favor, elija un idioma de destino", + "translate.pleaseLoadFile": "Por favor, suba un archivo primero", + "translate.contextEngineActive": "Motor contextual activo", + "translate.phase1": "Fase 1: Inicialización", + "translate.phase2": "Fase 2: Reconstrucción contextual", + "translate.stat.segments": "segmentos", + "translate.stat.precision": "precisión", + "translate.stat.speedLabel": "velocidad", + "translate.stat.turbo": "Turbo", + "translate.stat.time": "tiempo", + "translate.complete.masterQuality": "✓ Calidad maestra", + "translate.download": "Descargar", + "translate.newTranslation": "+ Nueva traducción", + "translate.failedTitle": "Error de traducción", + "translate.retry": "Reintentar", + "translate.uploadAnother": "Subir otro archivo", + "translate.monitor": "Monitor IA", + "translate.summary": "Resumen", + "translate.cancelProcess": "⟳ Cancelar el proceso", + "translate.layoutIntegrity": "Integridad del diseño", + "translate.secureHundred": "100% SEGURO", + "translate.okHundred": "100% OK", + "translate.preserveLayout": "Conservar diseño", + "translate.preserveLayoutDesc": "Conservar el diseño", + "translate.textOnly": "Solo texto", + "translate.textOnlyDesc": "Traducción rápida solo de texto", + "translate.unavailableStandard": "No disponible en modo Estándar (solo IA)" +} diff --git a/frontend/src/lib/i18n/messages/es/translateComplete.json b/frontend/src/lib/i18n/messages/es/translateComplete.json new file mode 100644 index 0000000..1d039ac --- /dev/null +++ b/frontend/src/lib/i18n/messages/es/translateComplete.json @@ -0,0 +1,6 @@ +{ + "translateComplete.highQuality": "Alta calidad", + "translateComplete.segments": "Segmentos", + "translateComplete.characters": "Caracteres", + "translateComplete.confidence": "Confianza" +} diff --git a/frontend/src/lib/i18n/messages/fa/admin.json b/frontend/src/lib/i18n/messages/fa/admin.json new file mode 100644 index 0000000..3eb361a --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/admin.json @@ -0,0 +1,48 @@ +{ + "admin.login.title": "مدیریت", + "admin.login.required": "ورود لازم است", + "admin.login.password": "رمز عبور مدیر", + "admin.login.connecting": "در حال اتصال...", + "admin.login.access": "دسترسی به پنل مدیریت", + "admin.login.restricted": "مختص مدیران", + "admin.layout.checking": "در حال تأیید احراز هویت...", + "admin.dashboard.title": "داشبورد مدیریت", + "admin.dashboard.subtitle": "پنل کنترل مدیر", + "admin.dashboard.refresh": "بازنشانی", + "admin.dashboard.refreshTooltip": "بازنشانی داده‌های داشبورد", + "admin.dashboard.config": "پیکربندی سیستم", + "admin.dashboard.maxFileSize": "حداکثر حجم فایل:", + "admin.dashboard.translationService": "سرویس ترجمه:", + "admin.dashboard.formats": "فرمت‌ها:", + "admin.nav.dashboard": "Dashboard", + "admin.nav.users": "کاربران", + "admin.nav.pricing": "قیمت‌ها و Stripe", + "admin.nav.providers": "ارائه‌دهندگان", + "admin.nav.system": "سیستم", + "admin.nav.logs": "گزارش‌ها", + "admin.users.title": "مدیریت کاربران", + "admin.users.subtitle": "مشاهده و مدیریت حساب‌های کاربری", + "admin.users.planUpdated": "طرح به‌روز شد", + "admin.users.planChanged": "طرح با موفقیت به \\\"{plan}\\\" تغییر کرد.", + "admin.users.unknownError": "خطای ناشناخته", + "admin.users.error": "خطا", + "admin.users.planUpdateError": "به‌روزرسانی طرح ممکن نیست: {message}", + "admin.users.noKeys": "بدون کلید", + "admin.users.noKeysDesc": "این کاربر کلید API فعالی ندارد.", + "admin.users.keysRevoked": "کلیدها ابطال شدند", + "admin.users.keysRevokedDesc": "{count} کلید API با موفقیت ابطال شد.", + "admin.users.revokeError": "ابطال کلیدها ممکن نیست: {message}", + "admin.users.retry": "تلاش مجدد", + "admin.system.title": "سیستم", + "admin.system.subtitle": "پایش وضعیت سیستم و مدیریت منابع", + "admin.system.quotas": "سهمیه‌های ترجمه", + "admin.system.resetQuotas": "بازنشانی سهمیه‌های ماهانه", + "admin.system.resetting": "در حال بازنشانی...", + "admin.system.reset": "بازنشانی", + "admin.system.allOperational": "تمام سیستم‌ها عملیاتی هستند", + "admin.system.issuesDetected": "مشکلات سیستمی شناسایی شد", + "admin.system.waitingData": "در انتظار داده...", + "admin.system.purging": "در حال پاکسازی...", + "admin.system.clean": "پاکسازی", + "admin.system.purge": "حذف کامل" +} diff --git a/frontend/src/lib/i18n/messages/fa/apiKeys.json b/frontend/src/lib/i18n/messages/fa/apiKeys.json new file mode 100644 index 0000000..5a02f31 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/apiKeys.json @@ -0,0 +1,72 @@ +{ + "apiKeys.webhook.title": "Intégration Webhook", + "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", + "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", + "apiKeys.webhook.codeParam": "webhook_url", + "apiKeys.title": "کلیدهای API", + "apiKeys.subtitle": "مدیریت کلیدهای API برای دسترسی برنامه‌نویسی به API ترجمه.", + "apiKeys.loading": "در حال بارگذاری...", + "apiKeys.sectionTitle": "API و خودکارسازی", + "apiKeys.sectionDesc": "تولید و مدیریت کلیدهای API برای گردش‌کار خودکارسازی", + "apiKeys.keysUsed": "{total} از {max} کلید استفاده شده", + "apiKeys.maxReached": "حداکثر کلیدها استفاده شده. یک کلید را لغو کنید تا کلید جدیدی بسازید.", + "apiKeys.canGenerate": "می‌توانید {count} کلید دیگر بسازید", + "apiKeys.canGeneratePlural": "می‌توانید {count} کلید دیگر بسازید", + "apiKeys.generateNew": "تولید کلید جدید", + "apiKeys.keyRevoked": "کلید لغو شد", + "apiKeys.keyRevokedDesc": "کلید API با موفقیت لغو شد.", + "apiKeys.keyNotFound": "کلید یافت نشد", + "apiKeys.keyNotFoundDesc": "کلید API دیگر وجود ندارد. ممکن است قبلاً لغو شده باشد.", + "apiKeys.error": "خطا", + "apiKeys.revokeError": "لغو کلید API ناموفق بود. لطفاً دوباره تلاش کنید.", + "apiKeys.limitReached": "محدودیت تکمیل شد", + "apiKeys.limitReachedDesc": "شما به حداکثر ۱۰ کلید API رسیده‌اید. یک کلید موجود را لغو کنید تا کلید جدیدی بسازید.", + "apiKeys.proRequired": "نیاز به ویژگی Pro", + "apiKeys.proRequiredDesc": "کلیدهای API یک ویژگی Pro هستند. لطفاً حساب خود را ارتقا دهید.", + "apiKeys.generateError": "تولید کلید API ناموفق بود. لطفاً دوباره تلاش کنید.", + "apiKeys.upgrade.title": "کلیدهای API", + "apiKeys.upgrade.subtitle": "ترجمه‌های خود را با دسترسی API خودکار کنید", + "apiKeys.upgrade.feat1": "تولید کلیدهای API نامحدود", + "apiKeys.upgrade.feat2": "خودکارسازی ترجمه اسناد", + "apiKeys.upgrade.feat3": "اعلان‌های Webhook", + "apiKeys.upgrade.feat4": "حالت‌های ترجمه LLM", + "apiKeys.upgrade.proFeature": "کلیدهای API یک ویژگی {pro} هستند. ارتقا دهید تا خودکارسازی API فعال شود.", + "apiKeys.upgrade.pro": "Pro", + "apiKeys.upgrade.cta": "ارتقا به Pro", + "apiKeys.dialog.maxTitle": "حداکثر کلیدها تکمیل شد", + "apiKeys.dialog.maxDesc": "شما به حداکثر ۱۰ کلید API رسیده‌اید. لطفاً قبل از تولید کلید جدید، یک کلید موجود را لغو کنید.", + "apiKeys.dialog.close": "بستن", + "apiKeys.dialog.generated": "کلید API تولید شد!", + "apiKeys.dialog.generatedDesc": "کلید API جدید شما ایجاد شد. اکنون آن را کپی کنید - دیگر نمایش داده نخواهد شد.", + "apiKeys.dialog.important": "مهم:", + "apiKeys.dialog.importantDesc": "این تنها باری است که این کلید را می‌بینید. آن را در جای امن نگه دارید.", + "apiKeys.dialog.apiKey": "کلید API", + "apiKeys.dialog.name": "نام:", + "apiKeys.dialog.done": "انجام شد", + "apiKeys.dialog.copied": "کلید را کپی کردم", + "apiKeys.dialog.generateTitle": "تولید کلید API جدید", + "apiKeys.dialog.generateDesc": "ایجاد کلید API جدید برای دسترسی برنامه‌نویسی به API ترجمه.", + "apiKeys.dialog.keyName": "نام کلید (اختیاری)", + "apiKeys.dialog.keyNamePlaceholder": "مثلاً: تولید، آزمایش", + "apiKeys.dialog.keyNameHint": "نامی توصیفی برای کمک به شناسایی این کلید در آینده.", + "apiKeys.dialog.nameTooLong": "نام باید {max} کاراکتر یا کمتر باشد", + "apiKeys.dialog.nameInvalid": "نام فقط می‌تواند شامل حروف، اعداد، فاصله، خط تیره و زیرخط باشد", + "apiKeys.dialog.cancel": "لغو", + "apiKeys.dialog.generating": "در حال تولید...", + "apiKeys.dialog.generate": "تولید کلید", + "apiKeys.table.name": "نام", + "apiKeys.table.prefix": "پیشوند", + "apiKeys.table.created": "تاریخ ایجاد", + "apiKeys.table.lastUsed": "آخرین استفاده", + "apiKeys.table.never": "هرگز", + "apiKeys.table.actions": "عملیات", + "apiKeys.table.revoke": "لغو", + "apiKeys.table.copyPrefix": "کپی پیشوند کلید", + "apiKeys.table.revokeKey": "لغو کلید", + "apiKeys.revokeDialog.title": "لغو کلید API", + "apiKeys.revokeDialog.desc": "آیا مطمئنید می‌خواهید کلید \\\"{name}\\\" را لغو کنید؟ این عمل قابل برگشت نیست.", + "apiKeys.revokeDialog.confirm": "بله، لغو کن", + "apiKeys.revokeDialog.cancel": "لغو", + "apiKeys.noKeysGenerated": "کلیدی تولید نشده", + "apiKeys.copied": "کپی شد!" +} diff --git a/frontend/src/lib/i18n/messages/fa/auth.json b/frontend/src/lib/i18n/messages/fa/auth.json new file mode 100644 index 0000000..b300370 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/auth.json @@ -0,0 +1,3 @@ +{ + "auth.brandName": "Wordly" +} diff --git a/frontend/src/lib/i18n/messages/fa/checkout.json b/frontend/src/lib/i18n/messages/fa/checkout.json new file mode 100644 index 0000000..77aa694 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/checkout.json @@ -0,0 +1,12 @@ +{ + "checkout.activating": "در حال فعال‌سازی…", + "checkout.activatingDesc": "در حال به‌روزرسانی اشتراک شما هستیم، لطفاً صبر کنید.", + "checkout.paymentConfirmed": "پرداخت تأیید شد!", + "checkout.subscriptionActivated": "اشتراک فعال شد!", + "checkout.planActivated": "پلن {plan} فعال شد!", + "checkout.redirectingToProfile": "در حال هدایت به نمایه شما…", + "checkout.paymentReceived": "پرداخت دریافت شد", + "checkout.redirecting": "در حال هدایت…", + "checkout.syncError": "خطای همگام‌سازی", + "checkout.networkError": "خطای شبکه. پرداخت شما تأیید شد — لطفاً نمایه خود را بارگیری مجدد کنید." +} diff --git a/frontend/src/lib/i18n/messages/fa/common.json b/frontend/src/lib/i18n/messages/fa/common.json new file mode 100644 index 0000000..8caec63 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/common.json @@ -0,0 +1,4 @@ +{ + "common.loading": "در حال بارگذاری...", + "common.backToHome": "بازگشت به صفحه اصلی" +} diff --git a/frontend/src/lib/i18n/messages/fa/context.json b/frontend/src/lib/i18n/messages/fa/context.json new file mode 100644 index 0000000..e6466fa --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/context.json @@ -0,0 +1,25 @@ +{ + "context.proTitle": "ویژگی Pro", + "context.proDesc": "زمینه و واژه‌نامه‌های حرفه‌ای با طرح‌های Pro، Business و Enterprise در دسترس هستند. آنها از طریق دستورالعمل‌ها و واژگان خاص حوزه شما، ترجمه‌های دقیق‌تری ارائه می‌دهند.", + "context.viewPlans": "مشاهده طرح‌ها", + "context.title": "زمینه و واژه‌نامه", + "context.subtitle": "با دستورالعمل‌ها و واژگان خاص حوزه خود، کیفیت ترجمه را بهبود ببخشید.", + "context.presets.title": "واژه‌نامه‌های حرفه‌ای", + "context.presets.desc": "بارگذاری واژه‌نامه کامل با دستورالعمل‌ها و اصطلاحات تخصصی", + "context.instructions.title": "دستورالعمل‌های زمینه", + "context.instructions.desc": "دستورالعمل‌هایی که هوش مصنوعی حین ترجمه پیروی می‌کند", + "context.instructions.placeholder": "مثال: شما اسناد فنی HVAC را ترجمه می‌کنید. از اصطلاحات دقیق مهندسی استفاده کنید...", + "context.glossary.title": "واژه‌نامه فنی", + "context.glossary.desc": "فرمت: source=target (یکی در هر خط). واژه‌نامه‌های بارگذاری‌شده از طریق پیش‌تنظیم قابل ویرایش هستند.", + "context.glossary.terms": "اصطلاح در واژه‌نامه", + "context.clearAll": "پاک کردن همه", + "context.saving": "در حال ذخیره...", + "context.save": "ذخیره", + "context.presets.createGlossary": "ایجاد واژه‌نامه", + "context.presets.created": "واژه‌نامه ایجاد شد", + "context.presets.createdDesc": "واژه‌نامه \\\"{name}\\\" با {count} واژه ایجاد شد.", + "context.presets.hint": "روی یک پیش‌تنظیم کلیک کنید تا واژه‌نامه‌ای با اصطلاحات تخصصی ایجاد شود. واژه‌نامه‌های خود را در بخش واژه‌نامه‌ها مدیریت کنید.", + "context.glossary.manage": "مدیریت واژه‌نامه‌ها", + "context.saved": "ذخیره شد", + "context.savedDesc": "دستورالعمل‌های زمینه شما ذخیره شد." +} diff --git a/frontend/src/lib/i18n/messages/fa/cookieConsent.json b/frontend/src/lib/i18n/messages/fa/cookieConsent.json new file mode 100644 index 0000000..eb7dd75 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/cookieConsent.json @@ -0,0 +1,7 @@ +{ + "cookieConsent.title": "کوکی‌ها در Wordly", + "cookieConsent.description": "ما از کوکی‌های ضروری برای کارکرد برنامه استفاده می‌کنیم (نشست، امنیت، زبان). با اجازه شما، از کوکی‌های اختیاری برای اندازه‌گیری ترافیک و بهبود محصول نیز استفاده می‌کنیم.", + "cookieConsent.acceptAll": "پذیرش همه", + "cookieConsent.essentialOnly": "فقط ضروری", + "cookieConsent.learnMore": "بیشتر بدانید" +} diff --git a/frontend/src/lib/i18n/messages/fa/dashboard.json b/frontend/src/lib/i18n/messages/fa/dashboard.json new file mode 100644 index 0000000..20803f4 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/dashboard.json @@ -0,0 +1,111 @@ +{ + "dashboard.nav.translate": "ترجمه", + "dashboard.nav.profile": "پروفایل من", + "dashboard.nav.settings": "تنظیمات", + "dashboard.nav.context": "زمینه", + "dashboard.nav.services": "خدمات", + "dashboard.nav.apiKeys": "کلیدهای API", + "dashboard.nav.glossaries": "واژه‌نامه‌ها", + "dashboard.header.title": "داشبورد", + "dashboard.header.subtitle": "مدیریت ترجمه‌های شما", + "dashboard.header.toggleMenu": "منو", + "dashboard.header.profileTitle": "پروفایل من", + "dashboard.sidebar.theme": "پوسته", + "dashboard.sidebar.signOut": "خروج", + "dashboard.sidebar.backHome": "بازگشت به صفحه اصلی", + "dashboard.sidebar.upgradeToPro": "ارتقا به Pro ←", + "dashboard.translate.pageTitle": "ترجمه یک سند", + "dashboard.translate.pageSubtitle": "یک فایل وارد کنید و زبان هدف را انتخاب کنید", + "dashboard.translate.errorNotificationTitle": "خطا", + "dashboard.translate.dropzone.uploadAria": "منطقه رها کردن فایل", + "dashboard.translate.dropzone.title": "فایل خود را اینجا بکشید و رها کنید", + "dashboard.translate.dropzone.subtitle": "یا کلیک کنید برای انتخاب (DOCX, XLSX, PPTX, PDF)", + "dashboard.translate.dropzone.replaceFile": "جایگزینی فایل", + "dashboard.translate.language.source": "زبان مبدأ", + "dashboard.translate.language.target": "زبان مقصد", + "dashboard.translate.language.loading": "در حال بارگذاری زبان‌ها…", + "dashboard.translate.language.autoDetect": "تشخیص خودکار", + "dashboard.translate.language.selectPlaceholder": "انتخاب…", + "dashboard.translate.language.loadErrorPrefix": "بارگذاری زبان‌ها ناموفق بود", + "dashboard.translate.provider.loading": "در حال بارگذاری ارائه‌دهنده‌ها…", + "dashboard.translate.provider.noneConfigured": "هیچ ارائه‌دهنده‌ای پیکربندی نشده", + "dashboard.translate.provider.modelTitle": "مدل", + "dashboard.translate.provider.sectionTitle": "ارائه‌دهنده", + "dashboard.translate.provider.llmDivider": "هوش مصنوعی · آگاه به زمینه", + "dashboard.translate.provider.llmDividerPro": "هوش مصنوعی · آگاه به زمینه (حرفه‌ای)", + "dashboard.translate.provider.upgrade": "ارتقا به حرفه‌ای", + "dashboard.translate.provider.upgradeSuffix": "برای دسترسی به ترجمه هوش مصنوعی", + "dashboard.translate.trust.zeroRetention": "بدون نگهداری", + "dashboard.translate.trust.deletedAfter": "فایل‌ها پس از پردازش حذف می‌شوند", + "dashboard.translate.actions.uploading": "در حال بارگذاری…", + "dashboard.translate.actions.translate": "ترجمه", + "dashboard.translate.actions.filePrefix": "فایل: ", + "dashboard.translate.actions.cancel": "انصراف", + "dashboard.translate.actions.tryAgain": "تلاش دوباره", + "dashboard.translate.steps.uploading": "در حال بارگذاری فایل…", + "dashboard.translate.steps.starting": "در حال شروع ترجمه…", + "dashboard.translate.complete.title": "ترجمه کامل شد!", + "dashboard.translate.complete.descNamed": "فایل {name} شما با موفقیت ترجمه شد.", + "dashboard.translate.complete.descGeneric": "فایل شما با موفقیت ترجمه شد.", + "dashboard.translate.complete.downloading": "در حال دانلود…", + "dashboard.translate.complete.download": "دانلود", + "dashboard.translate.complete.newTranslation": "ترجمه جدید", + "dashboard.translate.complete.toastOkTitle": "موفقیت", + "dashboard.translate.complete.toastOkDesc": "{name} با موفقیت بارگیری شد.", + "dashboard.translate.complete.toastFailTitle": "ناموفق", + "dashboard.translate.complete.toastFailDesc": "ترجمه ناموفق بود. لطفاً دوباره تلاش کنید.", + "dashboard.translate.sourceDocument": "سند مبدأ", + "dashboard.translate.configuration": "پیکربندی", + "dashboard.translate.translating": "در حال ترجمه", + "dashboard.translate.liveMonitor": "مانیتور زنده", + "dashboard.translate.summary": "خلاصه", + "dashboard.translate.engine": "موتور", + "dashboard.translate.confidence": "اطمینان", + "dashboard.translate.cancel": "لغو", + "dashboard.translate.segments": "بخش‌ها", + "dashboard.translate.characters": "نویسه‌ها", + "dashboard.translate.elapsed": "گذشته", + "dashboard.translate.segPerMin": "بخش/دقیقه", + "dashboard.translate.highQuality": "کیفیت بالا", + "dashboard.translate.quality": "کیفیت", + "dashboard.translate.completed": "ترجمه انجام شد", + "dashboard.translate.replace": "جایگزینی", + "dashboard.translate.pdfMode.title": "حالت ترجمه PDF", + "dashboard.translate.pdfMode.preserveLayout": "حفظ چیدمان", + "dashboard.translate.pdfMode.textOnly": "فقط متن", + "dashboard.translate.pdfMode.preserveLayoutDesc": "تصاویر، جداول و قالب‌بندی را حفظ می‌کند. مناسب PDFهای ساده.", + "dashboard.translate.pdfMode.textOnlyDesc": "تمام متن را کاملاً ترجمه می‌کند. خروجی تمیز، بدون مشکل چیدمان.", + "dashboard.translate.pipeline.upload": "بارگذاری", + "dashboard.translate.pipeline.analyze": "تحلیل", + "dashboard.translate.pipeline.translate": "ترجمه", + "dashboard.translate.pipeline.rebuild": "بازسازی", + "dashboard.translate.pipeline.finalize": "نهایی‌سازی", + "dashboard.translate.progress.processingFallback": "در حال پردازش…", + "dashboard.translate.progress.connectionLost": "اتصال قطع شد. در حال تلاش مجدد…", + "dashboard.translate.progress.failedTitle": "ترجمه ناموفق", + "dashboard.translate.error.unexpected": "خطای غیرمنتظره‌ای رخ داد. لطفاً دوباره تلاش کنید.", + "dashboard.translate.error.noResult": "ترجمه نتیجه‌ای نداشت. تأیید کنید که سند حاوی متن است، سپس دوباره تلاش کنید یا موتور دیگری انتخاب کنید.", + "dashboard.translate.error.apiKey": "کلید API نامعتبر یا ناموجود است. با مدیر تماس بگیرید تا کلیدها را پیکربندی کند.", + "dashboard.translate.error.quota": "محدودیت استفاده به پایان رسیده. چند دقیقه دیگر دوباره تلاش کنید یا موتور دیگری انتخاب کنید.", + "dashboard.translate.error.timeout": "اتصال به سرویس ترجمه منقضی شد. شبکه خود را بررسی کنید و دوباره تلاش کنید.", + "dashboard.translate.error.sessionExpired": "نشست منقضی شده. برای شروع مجدد ترجمه روی تلاش مجدد کلیک کنید.", + "dashboard.translate.error.empty": "سند خالی به نظر می‌رسد یا متن قابل ترجمه‌ای ندارد (تصویر PDF اسکن شده؟).", + "dashboard.translate.error.unsupported": "فرمت فایل پشتیبانی نمی‌شود یا فایل خراب است.", + "dashboard.translate.error.connection": "اتصال قطع شد. شبکه خود را بررسی کنید و دوباره تلاش کنید.", + "dashboard.translate.error.generic": "ترجمه ناموفق: {detail}", + "dashboard.translate.error.title": "ترجمه ناموفق", + "dashboard.translate.retry": "تلاش مجدد ترجمه", + "dashboard.translate.newFile": "فایل جدید", + "dashboard.translate.modeAI": "حالت هوش مصنوعی", + "dashboard.translate.modeClassic": "حالت کلاسیک", + "dashboard.translate.glossaryLLMHint": "واژه‌نامه‌ها در حالت هوش مصنوعی موجودند", + "dashboard.translate.submitting": "در حال ارسال...", + "dashboard.translate.submit": "شروع ترجمه", + "dashboard.translate.noFile": "ابتدا یک فایل آپلود کنید", + "dashboard.translate.noTargetLang": "زبان مقصد را انتخاب کنید", + "dashboard.topbar.interfaceLabel": "رابط ترجمه", + "dashboard.topbar.premiumAccess": "دسترسی ویژه", + "dashboard.checkoutSyncError": "خطا در همگام‌سازی پرداخت.", + "dashboard.networkRefresh": "خطای شبکه. لطفاً صفحه را تازه‌سازی کنید.", + "dashboard.continueToTranslate": "ادامه به ترجمه" +} diff --git a/frontend/src/lib/i18n/messages/fa/fileUploader.json b/frontend/src/lib/i18n/messages/fa/fileUploader.json new file mode 100644 index 0000000..7463ff2 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/fileUploader.json @@ -0,0 +1,31 @@ +{ + "fileUploader.uploadDocument": "بارگذاری سند", + "fileUploader.uploadDesc": "فایل را بکشید و رها کنید یا کلیک کنید (Excel, Word, PowerPoint)", + "fileUploader.dropHere": "فایل خود را اینجا رها کنید…", + "fileUploader.dragAndDrop": "سند خود را اینجا بکشید و رها کنید", + "fileUploader.orClickBrowse": "یا کلیک کنید برای مرور", + "fileUploader.preview": "پیش‌نمایش", + "fileUploader.translationOptions": "گزینه‌های ترجمه", + "fileUploader.configureSettings": "تنظیمات ترجمه را پیکربندی کنید", + "fileUploader.targetLanguage": "زبان مقصد", + "fileUploader.selectLanguage": "زبان را انتخاب کنید", + "fileUploader.translationProvider": "ارائه‌دهنده ترجمه", + "fileUploader.selectProvider": "ارائه‌دهنده را انتخاب کنید", + "fileUploader.advancedOptions": "گزینه‌های پیشرفته", + "fileUploader.translateImages": "ترجمه تصاویر", + "fileUploader.translating": "در حال ترجمه…", + "fileUploader.translateDocument": "ترجمه سند", + "fileUploader.processing": "در حال پردازش…", + "fileUploader.translationError": "خطای ترجمه", + "fileUploader.translationComplete": "ترجمه کامل شد!", + "fileUploader.translationCompleteDesc": "سند شما با حفظ تمام قالب‌بندی با موفقیت ترجمه شد.", + "fileUploader.download": "بارگیری سند ترجمه‌شده", + "fileUploader.webgpuUnsupported": "WebGPU در این مرورگر پشتیبانی نمی‌شود. لطفاً از Chrome 113+ یا Edge 113+ استفاده کنید.", + "fileUploader.webllmNotLoaded": "مدل WebLLM بارگذاری نشده است. به تنظیمات > سرویس‌های ترجمه بروید تا یک مدل بارگذاری کنید.", + "fileUploader.extracting": "در حال استخراج متن از سند…", + "fileUploader.noTranslatable": "متن قابل ترجمه در سند یافت نشد", + "fileUploader.foundTexts": "{count} متن برای ترجمه یافت شد", + "fileUploader.translatingItem": "در حال ترجمه {current}/{total}: \\\"{preview}\\\"", + "fileUploader.reconstructing": "در حال بازسازی سند…", + "fileUploader.translatingLocally": "ترجمه محلی با WebLLM…" +} diff --git a/frontend/src/lib/i18n/messages/fa/glossaries.json b/frontend/src/lib/i18n/messages/fa/glossaries.json new file mode 100644 index 0000000..11e0334 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/glossaries.json @@ -0,0 +1,189 @@ +{ + "glossaries.yourGlossaries": "واژه‌نامه‌های شما", + "glossaries.title": "واژه‌نامه‌ها و زمینه", + "glossaries.description": "واژه‌نامه‌ها و دستورالعمل‌های زمینه خود را برای ترجمه دقیق‌تر مدیریت کنید.", + "glossaries.createNew": "ایجاد جدید", + "glossaries.empty": "هنوز واژه‌نامه‌ای نیست", + "glossaries.emptyDesc": "اولین واژه‌نامه خود را ایجاد کنید یا یک پیش‌تنظیم حرفه‌ای بالا را بارگذاری کنید", + "glossaries.defineTerms": "واژه", + "glossaries.aboutTitle": "درباره واژه‌نامه‌ها", + "glossaries.aboutDesc": "واژه‌نامه‌ها به شما امکان تعریف ترجمه دقیق برای اصطلاحات خاص را می‌دهند. هنگام ترجمه، اصطلاحات واژه‌نامه برای اطمینان از ترجمه سازگار و دقیق استفاده می‌شوند.", + "glossaries.aboutFormat": "هر اصطلاح یک کلمه منبع و ترجمه‌هایی به چندین زبان دارد. در صفحه ترجمه یک واژه‌نامه را انتخاب کنید تا اعمال شود.", + "glossaries.toast.created": "واژه‌نامه ایجاد شد", + "glossaries.toast.createdDesc": "واژه‌نامه \\\"{name}\\\" ایجاد شد.", + "glossaries.toast.imported": "واژه‌نامه وارد شد", + "glossaries.toast.importedDesc": "واژه‌نامه \\\"{name}\\\" وارد شد.", + "glossaries.toast.updated": "واژه‌نامه به‌روزرسانی شد", + "glossaries.toast.updatedDesc": "واژه‌نامه \\\"{name}\\\" به‌روزرسانی شد.", + "glossaries.toast.deleted": "واژه‌نامه حذف شد", + "glossaries.toast.deletedDesc": "واژه‌نامه حذف شد.", + "glossaries.toast.error": "خطا", + "glossaries.toast.errorCreate": "ایجاد واژه‌نامه ناموفق بود", + "glossaries.toast.errorImport": "وارد کردن واژه‌نامه ناموفق بود", + "glossaries.toast.errorUpdate": "به‌روزرسانی واژه‌نامه ناموفق بود", + "glossaries.toast.errorDelete": "حذف واژه‌نامه ناموفق بود", + "glossaries.dialog.title": "واژه‌نامه جدید", + "glossaries.dialog.description": "یک واژه‌نامه برای ترجمه‌های خود بسازید", + "glossaries.dialog.nameLabel": "نام", + "glossaries.dialog.namePlaceholder": "واژه‌نامه من", + "glossaries.dialog.tabTemplates": "قالب‌ها", + "glossaries.dialog.tabFile": "فایل", + "glossaries.dialog.tabManual": "دستی", + "glossaries.dialog.cancel": "انصراف", + "glossaries.dialog.creating": "در حال ایجاد…", + "glossaries.dialog.importing": "در حال وارد کردن…", + "glossaries.dialog.importBtn": "وارد کردن", + "glossaries.dialog.selectPrompt": "انتخاب", + "glossaries.dialog.createBtn": "ایجاد", + "glossaries.dialog.createEmpty": "ایجاد خالی", + "glossaries.dialog.terms": "اصطلاحات", + "glossaries.dialog.templatesDesc": "یک قالب از پیش تعریف‌شده انتخاب کنید", + "glossaries.dialog.templatesEmpty": "قالبی موجود نیست", + "glossaries.dialog.dropTitle": "یک فایل CSV را اینجا بکشید", + "glossaries.dialog.dropOr": "یا", + "glossaries.dialog.dropFormats": "CSV, TSV, TXT", + "glossaries.termEditor.addTerm": "افزودن اصطلاح", + "glossaries.termEditor.maxReached": "حداکثر {max} اصطلاح برای هر واژه‌نامه رسیده است.", + "glossaries.dialog.formatTitle": "فرمت", + "glossaries.dialog.formatDesc": "مبدأ،مقصد (یکی در هر خط)", + "glossaries.dialog.formatNote": "خط اول در صورت شناسایی سرستون نادیده گرفته می‌شود", + "glossaries.dialog.errorFormat": "فرمت پشتیبانی نمی‌شود", + "glossaries.dialog.errorSize": "فایل بیش از حد بزرگ است", + "glossaries.dialog.errorEmpty": "فایل خالی", + "glossaries.dialog.errorRead": "خطای خواندن", + "glossaries.dialog.parsing": "در حال تجزیه…", + "glossaries.dialog.termsImported": "اصطلاح وارد شد", + "glossaries.dialog.changeFile": "تغییر فایل", + "glossaries.dialog.retry": "تلاش مجدد", + "glossaries.edit.title": "Modifier le glossaire", + "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", + "glossaries.edit.nameLabel": "Nom du glossaire", + "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", + "glossaries.edit.sourceLang": "Langue source", + "glossaries.edit.targetLang": "Langue cible", + "glossaries.edit.termsLabel": "Termes ({count} valides)", + "glossaries.edit.exportCsv": "Exporter CSV", + "glossaries.edit.importCsv": "Importer CSV", + "glossaries.edit.cancel": "Annuler", + "glossaries.edit.saving": "Enregistrement...", + "glossaries.edit.saveChanges": "Enregistrer les modifications", + "glossaries.edit.importFailedTitle": "Échec de l'importation", + "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", + "glossaries.edit.importSuccessTitle": "Importation réussie", + "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", + "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", + "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", + "glossaries.delete.title": "Supprimer le glossaire", + "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", + "glossaries.delete.warning": "Cette action est irréversible", + "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", + "glossaries.delete.cancel": "Annuler", + "glossaries.delete.deleting": "Suppression...", + "glossaries.delete.deleteBtn": "Supprimer", + "glossaries.upgrade.title": "Glossaires", + "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", + "glossaries.upgrade.feature1": "Créez plusieurs glossaires", + "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", + "glossaries.upgrade.feature3": "Importez/exportez via CSV", + "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", + "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", + "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", + "glossaries.upgrade.proLabel": "Pro", + "glossaries.upgrade.upgradeBtn": "Passer à Pro", + "glossaries.loading": "Chargement...", + "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", + "glossaries.howItWorks.step1Title": "Configurez ici", + "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", + "glossaries.howItWorks.step2Title": "Activez dans Traduire", + "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", + "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", + "glossaries.howItWorks.goToTranslate": "Aller à Traduire", + "glossaries.status.unsaved": "Non enregistré", + "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", + "glossaries.status.inactive": "Inactif", + "glossaries.instructions.whatForBold": "À quoi ça sert ?", + "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", + "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", + "glossaries.instructions.charCount": "{count} caractères", + "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", + "glossaries.instructions.clearAll": "Tout effacer", + "glossaries.instructions.saving": "Enregistrement…", + "glossaries.instructions.saved": "Enregistré", + "glossaries.presets.whatForBold": "À quoi ça sert ?", + "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", + "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", + "glossaries.presets.creating": "Création…", + "glossaries.presets.alreadyImported": "Déjà importé", + "glossaries.presets.it.title": "IT / Logiciel", + "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", + "glossaries.presets.legal.title": "Juridique / Contrats", + "glossaries.presets.legal.desc": "Droit des affaires, contentieux", + "glossaries.presets.medical.title": "Médical / Santé", + "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", + "glossaries.presets.finance.title": "Finance / Comptabilité", + "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", + "glossaries.presets.marketing.title": "Marketing / Publicité", + "glossaries.presets.marketing.desc": "Digital, branding, analytics", + "glossaries.presets.hr.title": "RH / Ressources Humaines", + "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", + "glossaries.presets.scientific.title": "Scientifique / Recherche", + "glossaries.presets.scientific.desc": "Publications, thèses, articles", + "glossaries.presets.ecommerce.title": "E-commerce / Vente", + "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", + "glossaries.grid.title": "Vos", + "glossaries.grid.titleHighlight": "glossaires", + "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", + "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", + "glossaries.grid.activeTranslation": "Traduction active :", + "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", + "glossaries.badge.compatible": "Compatible", + "glossaries.badge.otherTarget": "Autre cible", + "glossaries.card.editTerms": "Modifier les termes", + "glossaries.card.created": "ایجاد شد", + "glossaries.card.term": "اصطلاح", + "glossaries.card.delete": "Supprimer", + "glossaries.grid.searchPlaceholder": "Search a glossary…", + "glossaries.grid.noResults": "No results for this search.", + "glossaries.detail.backToList": "Back to glossaries", + "glossaries.detail.save": "Save", + "glossaries.detail.savedTitle": "Saved", + "glossaries.detail.savedDesc": "The glossary has been updated.", + "glossaries.detail.settingsTitle": "Settings", + "glossaries.detail.sourceLang": "Source language", + "glossaries.detail.targetLang": "Target language", + "glossaries.detail.termsTitle": "Terms", + "glossaries.detail.terms": "terms", + "glossaries.detail.searchTerms": "Filter…", + "glossaries.detail.noTerms": "No terms yet.", + "glossaries.detail.addFirstTerm": "Add the first term", + "glossaries.detail.addTerm": "Add a term", + "glossaries.detail.maxReached": "Maximum limit reached", + "glossaries.detail.source": "Source", + "glossaries.detail.target": "Target", + "glossaries.detail.sourcePlaceholder": "source term", + "glossaries.detail.targetPlaceholder": "target term", + "glossaries.detail.csvTitle": "CSV", + "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", + "glossaries.detail.export": "Export", + "glossaries.detail.import": "Import", + "glossaries.detail.dangerTitle": "Danger zone", + "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", + "glossaries.detail.deleteGlossary": "Delete this glossary", + "glossaries.detail.confirmDelete": "Confirm deletion?", + "glossaries.detail.confirm": "Confirm", + "glossaries.detail.cancel": "Cancel", + "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", + "glossaries.detail.sourceLocked": "fixed", + "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", + "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", + "glossaries.detail.notFoundTitle": "Glossary not found", + "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", + "glossaries.detail.maxTermsTitle": "Limit reached", + "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", + "glossaries.detail.importEmptyTitle": "Empty file", + "glossaries.detail.importEmptyDesc": "No terms detected in this file.", + "glossaries.detail.importedTitle": "Imported", + "glossaries.detail.importedDesc": "{count} terms imported.", + "glossaries.detail.importErrorTitle": "Read error", + "glossaries.detail.importErrorDesc": "Unable to read the file." +} diff --git a/frontend/src/lib/i18n/messages/fa/index.ts b/frontend/src/lib/i18n/messages/fa/index.ts new file mode 100644 index 0000000..5e2adb8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/index.ts @@ -0,0 +1,56 @@ +// Auto-generated by scripts/generate_i18n_index.py +// Merges all namespace JSON files for locale "fa". + +import admin from "./admin.json"; +import apiKeys from "./apiKeys.json"; +import auth from "./auth.json"; +import checkout from "./checkout.json"; +import common from "./common.json"; +import context from "./context.json"; +import cookieConsent from "./cookieConsent.json"; +import dashboard from "./dashboard.json"; +import fileUploader from "./fileUploader.json"; +import glossaries from "./glossaries.json"; +import landing from "./landing.json"; +import langSelector from "./langSelector.json"; +import layout from "./layout.json"; +import login from "./login.json"; +import memento from "./memento.json"; +import pricing from "./pricing.json"; +import profile from "./profile.json"; +import providerSelector from "./providerSelector.json"; +import providerTheme from "./providerTheme.json"; +import register from "./register.json"; +import services from "./services.json"; +import settings from "./settings.json"; +import translate from "./translate.json"; +import translateComplete from "./translateComplete.json"; + +const messages: Record = { + ...admin, + ...apiKeys, + ...auth, + ...checkout, + ...common, + ...context, + ...cookieConsent, + ...dashboard, + ...fileUploader, + ...glossaries, + ...landing, + ...langSelector, + ...layout, + ...login, + ...memento, + ...pricing, + ...profile, + ...providerSelector, + ...providerTheme, + ...register, + ...services, + ...settings, + ...translate, + ...translateComplete, +}; + +export default messages; diff --git a/frontend/src/lib/i18n/messages/fa/landing.json b/frontend/src/lib/i18n/messages/fa/landing.json new file mode 100644 index 0000000..f9d06d1 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/landing.json @@ -0,0 +1,146 @@ +{ + "landing.nav.why": "چرا ما؟", + "landing.nav.formats": "قالب‌ها", + "landing.nav.pricing": "قیمت‌ها", + "landing.nav.login": "ورود", + "landing.nav.startFree": "شروع رایگان", + "landing.hero.tag": "هوش مصنوعی حرفه‌ای اسناد", + "landing.hero.titleLine1": "اسناد خود را ترجمه کنید.", + "landing.hero.titleLine2": "با قالب‌بندی بی‌نقص.", + "landing.hero.description": "تنها مترجمی که SmartArt، نمودارها، فهرست مطالب، اشکال و طرح‌بندی‌های پیچیده را دقیقاً به شکلی که بوده حفظ می‌کند.", + "landing.hero.ctaMain": "شروع رایگان — ۲ سند/ماه", + "landing.hero.ctaSec": "مشاهده طرح‌ها", + "landing.hero.deleted": "فایل‌ها پس از ۶۰ دقیقه حذف می‌شوند", + "landing.hero.noHidden": "بدون هزینه پنهان", + "landing.hero.preview": "پیش‌نمایش قبل از پرداخت", + "landing.hero.formattedOk": "قالب‌بندی صحیح", + "landing.hero.aiActive": "ترجمه هوش مصنوعی فعال", + "landing.steps.title": "چگونه کار می‌کند؟", + "landing.steps.subtitle": "سه مرحله. صفر افت قالب‌بندی.", + "landing.steps.step1.num": "01", + "landing.steps.step1.title": "فایل خود را آپلود کنید", + "landing.steps.step1.desc": "فایل Excel، Word، PowerPoint یا PDF خود را بکشید و رها کنید.", + "landing.steps.step2.num": "02", + "landing.steps.step2.title": "زبان و موتور را انتخاب کنید", + "landing.steps.step2.desc": "زبان هدف و موتور را انتخاب کنید — کلاسیک یا هوش مصنوعی با درک زمینه.", + "landing.steps.step3.num": "03", + "landing.steps.step3.title": "نتیجه را دانلود کنید", + "landing.steps.step3.desc": "سند ترجمه‌شده با قالب‌بندی کاملاً مشابه اصل را دریافت کنید.", + "landing.features.tag": "موتور ترجمه هوش مصنوعی", + "landing.features.title": "ترجمه‌ای که تخصص شما را می‌فهمد", + "landing.features.description": "مدل‌های هوش مصنوعی ما زمینه را تحلیل می‌کنند، اصطلاحات شما را رعایت می‌کنند و حتی متن داخل تصاویر را ترجمه می‌کنند.", + "landing.features.context.title": "زمینه صنعت", + "landing.features.context.desc": "صنعت خود را توصیف کنید و ترجمه‌های تخصصی دریافت کنید، نه عمومی.", + "landing.features.glossary.title": "واژه‌نامه‌های تخصصی", + "landing.features.glossary.desc": "اصطلاحات فنی خود را تعریف کنید. CTA به معنی «واحد پردازش هوا» باقی می‌ماند، نه «فراخوان اقدام».", + "landing.features.vision.title": "تشخیص تصویر", + "landing.features.vision.desc": "متن تعبیه‌شده در تصاویر، نمودارها و گراف‌ها شناسایی و ترجمه می‌شود.", + "landing.features.demo.source": "مبدأ (FR)", + "landing.features.demo.google": "Google Translate", + "landing.features.demo.ours": "هوش مصنوعی ما", + "landing.layout.title": "قالب‌بندی شما،", + "landing.layout.title2": "کاملاً حفظ شده", + "landing.layout.subtitle": "سایر مترجم‌ها طرح‌بندی شما را خراب می‌کنند. ما نه.", + "landing.layout.p1.title": "SmartArt و نمودارها", + "landing.layout.p1.desc": "نمودارهای سازمانی، فلوچارت، سلسله‌مراتب — همه دقیقاً ترجمه شده.", + "landing.layout.p2.title": "فهرست مطالب", + "landing.layout.p2.desc": "مدخل‌های فهرست مطالب، شماره صفحات و ارجاعات متقاطع به‌درستی به‌روزرسانی می‌شوند.", + "landing.layout.p3.title": "نمودارها و گراف‌ها", + "landing.layout.p3.desc": "عناوین، برچسب‌های محور، راهنماها و نام سری‌ها — همه ترجمه شده.", + "landing.layout.p4.title": "اشکال و جعبه‌های متن", + "landing.layout.p4.desc": "مستطیل‌ها، بلوک‌های گرد، یادداشت‌ها — در همه‌جا بومی‌سازی شده.", + "landing.layout.p5.title": "سرصفحه و پاصفحه", + "landing.layout.p5.desc": "سرصفحه، پاصفحه و پاورقی هرگز فراموش نمی‌شوند.", + "landing.layout.p6.title": "۱۳۰+ زبان", + "landing.layout.p6.desc": "Google Translate، DeepL و موتورهای هوش مصنوعی حرفه‌ای.", + "landing.formats.title": "هر قالبی،", + "landing.formats.title2": "هر عنصری", + "landing.formats.subtitle": "آنچه دیگران فراموش می‌کنند را ترجمه می‌کنیم. کسب‌وکار شما مستندات بی‌نقص را شایسته است.", + "landing.formats.word.name": "Word", + "landing.formats.word.i1": "پاراگراف‌ها و عناوین", + "landing.formats.word.i2": "جداول و نمودارها", + "landing.formats.word.i3": "نمودارهای SmartArt", + "landing.formats.word.i4": "فهرست مطالب", + "landing.formats.word.i5": "سرصفحه و پاصفحه", + "landing.formats.word.i6": "اشکال و جعبه‌های متن", + "landing.formats.word.i7": "پاورقی و یادداشت‌های پایانی", + "landing.formats.excel.name": "Excel", + "landing.formats.excel.i1": "مقادیر سلول", + "landing.formats.excel.i2": "نام برگه‌ها", + "landing.formats.excel.i3": "نمودارها و برچسب‌ها", + "landing.formats.excel.i4": "سرصفحه و پاصفحه", + "landing.formats.excel.i5": "سلول‌های ادغام‌شده حفظ می‌شوند", + "landing.formats.pptx.name": "PowerPoint", + "landing.formats.pptx.i1": "متن اسلاید و یادداشت‌ها", + "landing.formats.pptx.i2": "نمودارها و گراف‌ها", + "landing.formats.pptx.i3": "اشکال و جعبه‌های متن", + "landing.formats.pptx.i4": "طرح‌بندی‌های اصلی", + "landing.formats.pptx.i5": "انیمیشن‌ها حفظ می‌شوند", + "landing.formats.pdf.name": "PDF", + "landing.formats.pdf.i1": "PDFهای متنی", + "landing.formats.pdf.i2": "طرح‌بندی حفظ شده", + "landing.formats.pdf.i3": "تصاویر در جای خود", + "landing.formats.pdf.i4": "جداول حفظ شده", + "landing.formats.pdf.i5": "خروجی به صورت DOCX یا PDF", + "landing.pricing.title": "قیمت‌های ساده و شفاف", + "landing.pricing.subtitle": "آنچه می‌بینید همان چیزی است که پرداخت می‌کنید. بدون هزینه پنهان.", + "landing.pricing.monthly": "ماهانه", + "landing.pricing.annual": "سالانه", + "landing.pricing.bestValue": "محبوب‌ترین", + "landing.pricing.month": "/ماه", + "landing.pricing.footer": "قیمت نمایش‌داده‌شده همان قیمتی است که پرداخت می‌کنید. بدون هزینه پنهان پس از ترجمه.", + "landing.pricing.starter.name": "Starter", + "landing.pricing.starter.desc": "برای افراد و پروژه‌های کوچک", + "landing.pricing.starter.f1": "۵۰ سند / ماه", + "landing.pricing.starter.f2": "تا ۵۰ صفحه برای هر سند", + "landing.pricing.starter.f3": "Google Translate + DeepL", + "landing.pricing.starter.f4": "فایل‌ها تا ۱۰ مگابایت", + "landing.pricing.starter.cta": "شروع کنید", + "landing.pricing.pro.name": "Pro", + "landing.pricing.pro.desc": "برای متخصصان حرفه‌ای", + "landing.pricing.pro.f1": "۲۰۰ سند / ماه", + "landing.pricing.pro.f2": "تا ۲۰۰ صفحه برای هر سند", + "landing.pricing.pro.f3": "ترجمه مبتنی بر هوش مصنوعی", + "landing.pricing.pro.f4": "Google + DeepL شامل است", + "landing.pricing.pro.f5": "واژه‌نامه و پرامپت سفارشی", + "landing.pricing.pro.f6": "پشتیبانی اولویت‌دار", + "landing.pricing.pro.cta": "Pro را امتحان کنید", + "landing.pricing.business.name": "سازمانی", + "landing.pricing.business.desc": "برای تیم‌ها با نیاز بالا", + "landing.pricing.business.f1": "۱,۰۰۰ سند / ماه", + "landing.pricing.business.f2": "تا ۵۰۰ صفحه برای هر سند", + "landing.pricing.business.f3": "هوش مصنوعی پیشرفته (Claude)", + "landing.pricing.business.f4": "همه ارائه‌دهندگان + API", + "landing.pricing.business.f5": "وب‌هوک و خودکارسازی", + "landing.pricing.business.f6": "۵ صندلی تیمی", + "landing.pricing.business.cta": "تماس با ما", + "landing.cta.title": "در ۳۰ ثانیه ترجمه را شروع کنید", + "landing.cta.subtitle": "بدون نیاز به کارت بانکی. همین الان رایگان امتحان کنید و به اسناد چندزبانه خود زندگی دوباره ببخشید.", + "landing.cta.button": "ایجاد حساب رایگان", + "landing.cta.secure": "محافظت‌شده با رمزنگاری AES-256", + "landing.footer.desc": "متخصص ترجمه هوشمند اسناد. هنر طرح‌بندی را با علم هوش مصنوعی زمینه‌محور ترکیب می‌کنیم.", + "landing.footer.product": "محصول", + "landing.footer.resources": "منابع", + "landing.footer.legal": "حقوقی", + "landing.footer.rights": "© 2026 Wordly.art — تمامی حقوق محفوظ است.", + "landing.hero.contextEngine": "ترجمه شناسایی شد: اصطلاح فنی نگهداری برای سیستم‌های تهویه...", + "landing.hero.liveAnalysis": "تحلیل زنده", + "landing.hero.termsDetected": "اصطلاح شناسایی شد", + "landing.steps.process": "فرآیند", + "landing.translate.newProject": "پروژه جدید", + "landing.translate.title": "ترجمه سند", + "landing.translate.subtitle": "فایل را وارد کنید و زبان مقصد را انتخاب کنید", + "landing.translate.sourceDocument": "سند منبع", + "landing.translate.configuration": "پیکربندی", + "landing.translate.sourceLang": "زبان منبع", + "landing.translate.targetLang": "زبان مقصد", + "landing.translate.provider": "ارائه‌دهنده", + "landing.translate.startTranslation": "شروع ترجمه", + "landing.translate.zeroRetention": "صفر نگهداری", + "landing.translate.filesDeleted": "فایل‌ها پس از پردازش حذف می‌شوند", + "landing.translate.dropHere": "اینجا بکشید و رها کنید", + "landing.translate.supportedFormats": "فایل‌های DOCX, XLSX, PPTX یا PDF پشتیبانی می‌شوند", + "landing.translate.aiAnalysis": "تحلیل AI فعال", + "landing.translate.processing": "در حال پردازش", + "landing.translate.preservingLayout": "طرح‌بندی شما حفظ می‌شود" +} diff --git a/frontend/src/lib/i18n/messages/fa/langSelector.json b/frontend/src/lib/i18n/messages/fa/langSelector.json new file mode 100644 index 0000000..e8c3d2c --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/langSelector.json @@ -0,0 +1,7 @@ +{ + "langSelector.search": "جستجو…", + "langSelector.noResults": "بدون نتیجه", + "langSelector.source": "مبدأ", + "langSelector.target": "هدف", + "langSelector.swap": "جابجایی" +} diff --git a/frontend/src/lib/i18n/messages/fa/layout.json b/frontend/src/lib/i18n/messages/fa/layout.json new file mode 100644 index 0000000..8ad7790 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/layout.json @@ -0,0 +1,5 @@ +{ + "layout.nav.apiAccess": "دسترسی API", + "layout.footer.terms": "شرایط", + "layout.footer.privacy": "حریم خصوصی" +} diff --git a/frontend/src/lib/i18n/messages/fa/login.json b/frontend/src/lib/i18n/messages/fa/login.json new file mode 100644 index 0000000..300cbbe --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/login.json @@ -0,0 +1,6 @@ +{ + "login.orContinueWith": "یا با ایمیل ادامه دهید", + "login.google.connecting": "در حال اتصال…", + "login.google.errorGeneric": "خطایی در ورود با Google رخ داد.", + "login.google.errorFailed": "ورود با Google ناموفق بود. دوباره تلاش کنید." +} diff --git a/frontend/src/lib/i18n/messages/fa/memento.json b/frontend/src/lib/i18n/messages/fa/memento.json new file mode 100644 index 0000000..5d79dea --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/memento.json @@ -0,0 +1,6 @@ +{ + "memento.title": "Momento را کشف کنید", + "memento.slogan": "Momento فقط یک برنامه یادداشت نیست. یک اکوسیستم هوشمند است که با استفاده از ۶ عامل هوش مصنوعی و جستجوی معنایی پیشرفته، ایده‌های شما را در زمان واقعی متصل، تحلیل و توسعه می‌دهد.", + "memento.ctaFree": "رایگان شروع کنید", + "memento.ctaMore": "بیشتر بدانید" +} diff --git a/frontend/src/lib/i18n/messages/fa/pricing.json b/frontend/src/lib/i18n/messages/fa/pricing.json new file mode 100644 index 0000000..470c550 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/pricing.json @@ -0,0 +1,151 @@ +{ + "pricing.nav.back": "بازگشت", + "pricing.nav.home": "خانه", + "pricing.nav.mySubscription": "اشتراک من", + "pricing.header.badge": "مدل‌های هوش مصنوعی به‌روزرسانی شدند — مارس ۲۰۲۶", + "pricing.header.title": "طرحی برای هر نیازی", + "pricing.header.subtitle": "اسناد Word، Excel و PowerPoint خود را با حفظ قالب‌بندی اصلی ترجمه کنید. بدون نیاز به کلید API.", + "pricing.billing.monthly": "ماهانه", + "pricing.billing.yearly": "سالانه", + "pricing.plans.free.name": "رایگان", + "pricing.plans.starter.name": "مبتدی", + "pricing.plans.pro.name": "حرفه‌ای", + "pricing.plans.business.name": "سازمانی", + "pricing.plans.enterprise.name": "شرکتی", + "pricing.plans.free.description": "مناسب برای آشنایی با برنامه", + "pricing.plans.starter.description": "برای افراد و پروژه‌های کوچک", + "pricing.plans.pro.description": "برای متخصصان و تیم‌های در حال رشد", + "pricing.plans.business.description": "برای تیم‌ها و سازمان‌ها", + "pricing.plans.enterprise.description": "راه‌حل‌های سفارشی برای سازمان‌های بزرگ", + "pricing.plans.pro.highlight": "محبوب‌ترین", + "pricing.plans.pro.badge": "محبوب", + "pricing.plans.enterprise.badge": "درخواستی", + "pricing.plans.free.feat1": "۵ سند / ماه", + "pricing.plans.free.feat2": "تا ۱۵ صفحه برای هر سند", + "pricing.plans.free.feat3": "Google Translation شامل", + "pricing.plans.free.feat4": "تمام زبان‌ها (۱۳۰+)", + "pricing.plans.free.feat5": "پشتیبانی انجمن", + "pricing.plans.starter.feat1": "۵۰ سند / ماه", + "pricing.plans.starter.feat2": "تا ۵۰ صفحه برای هر سند", + "pricing.plans.starter.feat3": "Google Translation + DeepL", + "pricing.plans.starter.feat4": "فایل‌ها تا ۱۰ مگابایت", + "pricing.plans.starter.feat5": "پشتیبانی ایمیل", + "pricing.plans.starter.feat6": "تاریخچه ۳۰ روزه", + "pricing.plans.pro.feat1": "۲۰۰ سند / ماه", + "pricing.plans.pro.feat2": "تا ۲۰۰ صفحه برای هر سند", + "pricing.plans.pro.feat3": "ترجمه هوش مصنوعی Essential", + "pricing.plans.pro.feat4": "Google Translation + DeepL", + "pricing.plans.pro.feat5": "فایل‌ها تا ۲۵ مگابایت", + "pricing.plans.pro.feat6": "واژه‌نامه‌های سفارشی", + "pricing.plans.pro.feat7": "پشتیبانی اولویت‌دار", + "pricing.plans.pro.feat8": "تاریخچه ۹۰ روزه", + "pricing.plans.business.feat1": "۱,۰۰۰ سند / ماه", + "pricing.plans.business.feat2": "تا ۵۰۰ صفحه برای هر سند", + "pricing.plans.business.feat3": "هوش مصنوعی پایه + پیشرفته (Claude Haiku)", + "pricing.plans.business.feat4": "تمام ارائه‌دهنده‌های ترجمه", + "pricing.plans.business.feat5": "فایل‌ها تا ۵۰ مگابایت", + "pricing.plans.business.feat6": "دسترسی API (۱۰,۰۰۰ فراخوان/ماه)", + "pricing.plans.business.feat7": "وب‌هوک اعلان", + "pricing.plans.business.feat8": "پشتیبانی اختصاصی", + "pricing.plans.business.feat9": "تاریخچه ۱ ساله", + "pricing.plans.business.feat10": "تحلیل پیشرفته", + "pricing.plans.enterprise.feat1": "اسناد نامحدود", + "pricing.plans.enterprise.feat2": "تمام مدل‌های هوش مصنوعی (GPT-5, Claude Opus 4.6…)", + "pricing.plans.enterprise.feat3": "استقرار محلی یا ابری اختصاصی", + "pricing.plans.enterprise.feat4": "SLA 99.9% تضمین‌شده", + "pricing.plans.enterprise.feat5": "پشتیبانی اختصاصی ۲۴/۷", + "pricing.plans.enterprise.feat6": "برند سفارشی", + "pricing.plans.enterprise.feat7": "تیم‌های نامحدود", + "pricing.plans.enterprise.feat8": "یکپارچه‌سازی سفارشی", + "pricing.card.onRequest": "درخواستی", + "pricing.card.free": "رایگان", + "pricing.card.perMonth": "/ماه", + "pricing.card.billedYearly": "{price} € / سال صورتحساب", + "pricing.card.documents": "اسناد", + "pricing.card.pagesMax": "حداکثر صفحات", + "pricing.card.aiTranslation": "ترجمه هوش مصنوعی", + "pricing.card.unlimited": "نامحدود", + "pricing.card.perMonthStat": "/ ماه", + "pricing.card.perDoc": "ص / سند", + "pricing.card.aiEssential": "پایه", + "pricing.card.aiEssentialPremium": "پایه + پیشرفته", + "pricing.card.aiCustom": "سفارشی", + "pricing.card.myPlan": "طرح من", + "pricing.card.managePlan": "مدیریت طرح من", + "pricing.card.startFree": "رایگان شروع کنید", + "pricing.card.contactUs": "تماس با ما", + "pricing.card.choosePlan": "انتخاب این طرح", + "pricing.card.processing": "در حال پردازش…", + "pricing.comparison.title": "مقایسه تفصیلی", + "pricing.comparison.subtitle": "همه موارد شامل هر طرح", + "pricing.comparison.feature": "ویژگی", + "pricing.comparison.docsPerMonth": "اسناد / ماه", + "pricing.comparison.pagesMaxPerDoc": "حداکثر صفحات / سند", + "pricing.comparison.maxFileSize": "حداکثر حجم فایل", + "pricing.comparison.googleTranslation": "Google Translation", + "pricing.comparison.deepl": "DeepL", + "pricing.comparison.aiEssential": "ترجمه هوش مصنوعی پایه", + "pricing.comparison.aiPremium": "ترجمه هوش مصنوعی پیشرفته", + "pricing.comparison.apiAccess": "دسترسی API", + "pricing.comparison.priorityProcessing": "پردازش اولویت‌دار", + "pricing.comparison.support": "پشتیبانی", + "pricing.comparison.support.community": "انجمن", + "pricing.comparison.support.email": "ایمیل", + "pricing.comparison.support.priority": "اولویت‌دار", + "pricing.comparison.support.dedicated": "اختصاصی", + "pricing.comparison.mb": "مگابایت", + "pricing.credits.title": "اعتبارات اضافی", + "pricing.credits.subtitle": "بیشتر نیاز دارید؟ اعتبار تکی بخرید، بدون اشتراک.", + "pricing.credits.perPage": "۱ اعتبار = ۱ صفحه ترجمه‌شده.", + "pricing.credits.bestValue": "بهترین ارزش", + "pricing.credits.unit": "اعتبار", + "pricing.credits.centsPerCredit": "سنت / اعتبار", + "pricing.credits.buy": "خرید", + "pricing.trust.encryption.title": "رمزنگاری سرتاسری", + "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 در حالت استراحت", + "pricing.trust.languages.title": "۱۳۰+ زبان", + "pricing.trust.languages.sub": "شامل عربی، فارسی، عبری (RTL)", + "pricing.trust.parallel.title": "پردازش موازی", + "pricing.trust.parallel.sub": "هوش مصنوعی چندنخی فوق‌سریع", + "pricing.trust.availability.title": "۲۴/۷ در دسترس", + "pricing.trust.availability.sub": "۹۹.۹٪ زمان فعالیت تضمین‌شده", + "pricing.aiModels.title": "مدل‌های هوش مصنوعی ما — مارس ۲۰۲۶", + "pricing.aiModels.essential.title": "ترجمه هوش مصنوعی پایه", + "pricing.aiModels.essential.plan": "طرح حرفه‌ای", + "pricing.aiModels.essential.descPrefix": "مبتنی بر", + "pricing.aiModels.essential.descSuffix": "— مقرون‌به‌صرفه‌ترین مدل هوش مصنوعی سال ۲۰۲۶. کیفیت قابل مقایسه با مدل‌های پیشرو با کسر هزینه.", + "pricing.aiModels.essential.modelName": "مدل هوش مصنوعی Essential", + "pricing.aiModels.essential.context": "۱۶۳هزار توکن زمینه", + "pricing.aiModels.essential.value": "ارزش عالی نسبت به قیمت", + "pricing.aiModels.premium.title": "ترجمه هوش مصنوعی پیشرفته", + "pricing.aiModels.premium.plan": "طرح سازمانی", + "pricing.aiModels.premium.descPrefix": "مبتنی بر", + "pricing.aiModels.premium.descSuffix": "توسط Anthropic — دقیق در اسناد حقوقی، پزشکی و فنی پیچیده.", + "pricing.aiModels.premium.context": "۲۰۰هزار توکن زمینه", + "pricing.aiModels.premium.precision": "بالاترین دقت", + "pricing.faq.title": "سوالات متداول", + "pricing.faq.q1": "آیا می‌توانم طرح را هر زمان بخواهم تغییر دهم؟", + "pricing.faq.a1": "بله. ارتقا فوری و به‌نسبت است. تنزل در پایان دوره جاری اعمال می‌شود.", + "pricing.faq.q2": "\\\"ترجمه هوش مصنوعی پایه\\\" چیست؟", + "pricing.faq.a2": "این موتور هوش مصنوعی ماست. زمینه اسناد شما را درک می‌کند، طرح‌بندی را حفظ می‌کند و اصطلاحات فنی را بسیار بهتر از ترجمه کلاسیک مدیریت می‌کند.", + "pricing.faq.q3": "تفاوت هوش مصنوعی پایه و پیشرفته چیست؟", + "pricing.faq.a3": "هوش مصنوعی Essential از یک مدل بهینه‌شده استفاده می‌کند (ارزش عالی برای پول). هوش مصنوعی Premium از Claude 3.5 Haiku انترپیک استفاده می‌کند که در اسناد حقوقی، پزشکی و فنی پیچیده دقیق‌تر است.", + "pricing.faq.q4": "آیا اسناد من پس از ترجمه نگهداری می‌شوند؟", + "pricing.faq.a4": "فایل‌های ترجمه‌شده طبق طرح شما در دسترس هستند (۳۰ روز مبتدی، ۹۰ روز حرفه‌ای، ۱ سال سازمانی). آنها در حالت استراحت و هنگام انتقال رمزنگاری می‌شوند.", + "pricing.faq.q5": "اگر از سهمیه ماهانه خود فراتر رویم چه می‌شود؟", + "pricing.faq.a5": "می‌توانید اعتبار اضافی تکی بخرید یا طرح خود را ارتقا دهید. در ۸۰٪ مصرف به شما اطلاع داده می‌شود.", + "pricing.faq.q6": "آیا دوره آزمایشی رایگان برای طرح‌های پولی وجود دارد؟", + "pricing.faq.a6": "طرح رایگان دائمی است و نیاز به کارت اعتباری ندارد. برای طرح‌های حرفه‌ای و سازمانی، برای دوره آزمایشی ۱۴ روزه با ما تماس بگیرید.", + "pricing.faq.q7": "چه فرمت‌های فایلی پشتیبانی می‌شوند؟", + "pricing.faq.a7": "Word (.docx)، Excel (.xlsx/.xls)، PowerPoint (.pptx) و به‌زودی PDF. تمام طرح‌ها از فرمت‌های یکسان پشتیبانی می‌کنند.", + "pricing.cta.title": "آماده شروع هستید؟", + "pricing.cta.subtitle": "رایگان شروع کنید، بدون نیاز به کارت اعتباری. هر زمان که نیاز داشتید ارتقا دهید.", + "pricing.cta.createAccount": "ایجاد حساب رایگان", + "pricing.cta.login": "ورود", + "pricing.toast.demo": "حالت نمایشی — Stripe هنوز پیکربندی نشده. در محیط عملیاتی، برای فعال‌سازی طرح {planId} به صفحه پرداخت هدایت می‌شوید.", + "pricing.toast.networkError": "خطای شبکه. لطفاً دوباره تلاش کنید.", + "pricing.toast.paymentError": "خطا در ایجاد پرداخت.", + "pricing.dashboard": "داشبورد", + "pricing.okSymbol": "✓", + "pricing.errSymbol": "✕" +} diff --git a/frontend/src/lib/i18n/messages/fa/profile.json b/frontend/src/lib/i18n/messages/fa/profile.json new file mode 100644 index 0000000..275ae1d --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/profile.json @@ -0,0 +1,58 @@ +{ + "profile.header.title": "پروفایل من", + "profile.header.subtitle": "مدیریت حساب و تنظیمات شما.", + "profile.tabs.account": "حساب کاربری", + "profile.tabs.subscription": "اشتراک", + "profile.tabs.preferences": "تنظیمات", + "profile.account.user": "کاربر", + "profile.account.memberSince": "عضو از", + "profile.plan.label": "طرح", + "profile.plan.free": "رایگان", + "profile.plan.starter": "Starter", + "profile.plan.pro": "Pro", + "profile.plan.business": "Business", + "profile.plan.enterprise": "Enterprise", + "profile.plan.pricePerMonth": "{price} €/ماه", + "profile.subscription.canceling": "در حال لغو", + "profile.subscription.active": "فعال", + "profile.subscription.unknown": "نامشخص", + "profile.subscription.accessUntil": "دسترسی تا", + "profile.subscription.renewalOn": "تمدید در", + "profile.subscription.upgradePlan": "ارتقا به طرح پولی", + "profile.subscription.changePlan": "تغییر طرح", + "profile.subscription.manageBilling": "مدیریت صورتحساب", + "profile.subscription.billingUnavailable": "پورتال صورتحساب در دسترس نیست.", + "profile.subscription.billingError": "خطا در دسترسی به پورتال صورتحساب.", + "profile.subscription.cancelSuccess": "اشتراک لغو شد. تا پایان دوره فعلی به خدمات دسترسی خواهید داشت.", + "profile.subscription.cancelError": "خطا هنگام لغو.", + "profile.subscription.networkError": "خطای شبکه.", + "profile.usage.title": "مصرف این ماه", + "profile.usage.resetOn": "بازنشانی در", + "profile.usage.documents": "اسناد", + "profile.usage.pages": "صفحات", + "profile.usage.extraCredits": "اعتبار اضافی", + "profile.usage.extraCreditsPlural": "اعتبارهای اضافی", + "profile.usage.quotaReached": "سهمیه تمام شده", + "profile.usage.quotaReachedDesc": "برای ادامه، به طرح بالاتر ارتقا دهید.", + "profile.usage.unlockMore": "با طرح پولی ترجمه‌های بیشتری داشته باشید.", + "profile.usage.viewPlans": "مشاهده طرح‌ها", + "profile.usage.includedInPlan": "شامل طرح شما", + "profile.danger.title": "منطقه خطر", + "profile.danger.description": "لغو در پایان دوره فعلی اعمال می‌شود. تا آن تاریخ به خدمات خود دسترسی خواهید داشت.", + "profile.danger.confirm": "مطمئن هستید؟ این عمل قابل برگشت نیست.", + "profile.danger.confirmCancel": "تأیید لغو", + "profile.danger.cancelSubscription": "لغو اشتراک من", + "profile.danger.keep": "خیر، نگه دار", + "profile.prefs.interfaceLang": "زبان رابط کاربری", + "profile.prefs.interfaceLangDesc": "زبان به‌طور خودکار بر اساس مرورگر شما شناسایی می‌شود. می‌توانید آن را به‌صورت دستی تغییر دهید.", + "profile.prefs.defaultTargetLang": "زبان هدف پیش‌فرض", + "profile.prefs.selectLanguage": "انتخاب زبان", + "profile.prefs.defaultTargetLangDesc": "این زبان برای ترجمه‌های شما از پیش انتخاب خواهد شد.", + "profile.prefs.save": "ذخیره", + "profile.prefs.theme": "پوسته", + "profile.prefs.themeDesc": "ظاهر رابط کاربری را انتخاب کنید", + "profile.prefs.cache": "حافظه پنهان", + "profile.prefs.cacheDesc": "پاک کردن حافظه پنهان محلی ممکن است برخی مشکلات نمایش را برطرف کند.", + "profile.prefs.clearing": "در حال پاک کردن...", + "profile.prefs.clearCache": "پاک کردن حافظه پنهان" +} diff --git a/frontend/src/lib/i18n/messages/fa/providerSelector.json b/frontend/src/lib/i18n/messages/fa/providerSelector.json new file mode 100644 index 0000000..0ab89dc --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/providerSelector.json @@ -0,0 +1,7 @@ +{ + "providerSelector.noClassic": "مترجم استاندارد موجود نیست.", + "providerSelector.noLlm": "هیچ مدل هوش مصنوعی پیکربندی نشده است.", + "providerSelector.costOne": "هزینه: 1 اعتبار در هر صفحه", + "providerSelector.costFive": "هزینه: 5 اعتبار در هر صفحه (ضریب ویژه)", + "providerSelector.unlockContextual": "ترجمه زمینه‌ای ویژه را برای کل اسناد خود فعال کنید." +} diff --git a/frontend/src/lib/i18n/messages/fa/providerTheme.json b/frontend/src/lib/i18n/messages/fa/providerTheme.json new file mode 100644 index 0000000..7009e4e --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/providerTheme.json @@ -0,0 +1,29 @@ +{ + "providerTheme.deepseek.badge": "اساسی", + "providerTheme.deepseek.subBadge": "فنی و اقتصادی", + "providerTheme.deepseek.desc": "ترجمه فوق‌دقیق و اقتصادی، ایده‌آل برای اسناد فنی و کد.", + "providerTheme.openai.badge": "ویژه", + "providerTheme.openai.subBadge": "وفاداری بالا", + "providerTheme.openai.desc": "استاندارد جهانی هوش مصنوعی. حداکثر سازگاری متنی و رعایت دقیق سبک.", + "providerTheme.minimax.badge": "پیشرفته", + "providerTheme.minimax.subBadge": "عملکرد", + "providerTheme.minimax.desc": "سرعت اجرای باورنکردنی و درک عالی از ساختارهای پیچیده.", + "providerTheme.openrouter.badge": "سریع", + "providerTheme.openrouter.subBadge": "چند مدل", + "providerTheme.openrouter.desc": "دسترسی یکپارچه به بهترین مدل‌های متن‌باز بهینه‌سازی‌شده برای ترجمه.", + "providerTheme.openrouter_premium.badge": "فوق‌العاده", + "providerTheme.openrouter_premium.subBadge": "حداکثر زمینه", + "providerTheme.openrouter_premium.desc": "با کمک مدل‌های پیشرفته (GPT-4o، Claude Sonnet 4.6) برای اسناد طولانی.", + "providerTheme.zai.badge": "تخصصی", + "providerTheme.zai.subBadge": "مالی و حقوقی", + "providerTheme.zai.desc": "مدل تنظیم‌شده برای اصطلاحات تجاری سخت‌گیرانه (حقوقی، مالی).", + "providerTheme.default.badge": "مدرن", + "providerTheme.default.subBadge": "استدلال هوش مصنوعی", + "providerTheme.default.desc": "ترجمه مدل زبانی بزرگ (LLM) با تحلیل معنایی پیشرفته.", + "providerTheme.classic.google.label": "ترجمه Google", + "providerTheme.classic.google.desc": "ترجمه فوق‌سریع با پوشش بیش از 130 زبان. برای جریان‌های عمومی توصیه می‌شود.", + "providerTheme.classic.deepl.label": "DeepL Pro", + "providerTheme.classic.deepl.desc": "ترجمه با دقت بالا که به دلیل روانی و عبارات طبیعی شهرت دارد.", + "providerTheme.classic.google_cloud.label": "Google Cloud API", + "providerTheme.classic.google_cloud.desc": "موتور ابری حرفه‌ای بهینه‌سازی‌شده برای پردازش حجم زیاد اسناد." +} diff --git a/frontend/src/lib/i18n/messages/fa/register.json b/frontend/src/lib/i18n/messages/fa/register.json new file mode 100644 index 0000000..1bf5b8f --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/register.json @@ -0,0 +1,29 @@ +{ + "register.title": "ایجاد حساب کاربری", + "register.subtitle": "ترجمه را رایگان شروع کنید", + "register.error.failed": "ثبت‌نام ناموفق بود", + "register.name.label": "نام", + "register.name.placeholder": "نام شما", + "register.name.error": "نام باید حداقل ۲ کاراکتر باشد", + "register.email.label": "آدرس ایمیل", + "register.email.placeholder": "you@example.com", + "register.email.error": "آدرس ایمیل نامعتبر", + "register.password.label": "رمز عبور", + "register.password.error": "رمز عبور باید حداقل ۸ کاراکتر با یک حرف بزرگ، یک حرف کوچک و یک عدد باشد", + "register.password.show": "نمایش رمز عبور", + "register.password.hide": "مخفی کردن رمز عبور", + "register.password.strengthLabel": "قدرت:", + "register.password.strength.weak": "ضعیف", + "register.password.strength.medium": "متوسط", + "register.password.strength.strong": "قوی", + "register.confirmPassword.label": "تأیید رمز عبور", + "register.confirmPassword.error": "رمزهای عبور مطابقت ندارند", + "register.confirmPassword.show": "نمایش", + "register.confirmPassword.hide": "مخفی", + "register.submit.creating": "در حال ایجاد حساب...", + "register.submit.create": "حساب من را بساز", + "register.hasAccount": "قبلاً حساب دارید؟", + "register.login": "وارد شوید", + "register.terms.prefix": "با ایجاد حساب، شما می‌پذیرید", + "register.terms.link": "شرایط خدمات" +} diff --git a/frontend/src/lib/i18n/messages/fa/services.json b/frontend/src/lib/i18n/messages/fa/services.json new file mode 100644 index 0000000..c7fc34d --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/services.json @@ -0,0 +1,14 @@ +{ + "services.title": "ارائه‌دهندگان ترجمه", + "services.subtitle": "ارائه‌دهندگان توسط مدیر پیکربندی شده‌اند. می‌توانید ببینید کدام‌یک برای حساب شما فعال است.", + "services.loading": "در حال بارگذاری ارائه‌دهندگان...", + "services.noProviders": "در حال حاضر هیچ ارائه‌دهنده‌ای پیکربندی نشده. با مدیر تماس بگیرید.", + "services.classic": "ترجمه کلاسیک", + "services.llmPro": "LLM · مبتنی بر زمینه (Pro)", + "services.available": "در دسترس", + "services.model": "مدل", + "services.adminOnly.title": "پیکربندی ارائه‌دهنده فقط برای مدیر", + "services.adminOnly.desc": "کلیدهای API، انتخاب مدل و فعال‌سازی ارائه‌دهنده منحصراً توسط مدیر در پنل مدیریت انجام می‌شود. شما هرگز نیازی به وارد کردن کلید API ندارید.", + "services.fallback.google.label": "ترجمه Google", + "services.fallback.google.desc": "ترجمه سریع، بیش از 130 زبان" +} diff --git a/frontend/src/lib/i18n/messages/fa/settings.json b/frontend/src/lib/i18n/messages/fa/settings.json new file mode 100644 index 0000000..3500bd2 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/settings.json @@ -0,0 +1,20 @@ +{ + "settings.title": "تنظیمات", + "settings.subtitle": "پیکربندی عمومی برنامه", + "settings.formats.title": "فرمت‌های پشتیبانی شده", + "settings.formats.subtitle": "انواع سند قابل ترجمه", + "settings.formats.formulas": "فرمول‌ها", + "settings.formats.styles": "سبک‌ها", + "settings.formats.images": "تصاویر", + "settings.formats.headers": "سرصفحه‌ها", + "settings.formats.tables": "جداول", + "settings.formats.slides": "اسلایدها", + "settings.formats.notes": "یادداشت‌ها", + "settings.cache.title": "حافظه پنهان", + "settings.cache.desc": "پاک کردن حافظه پنهان محلی ممکن است برخی مشکلات نمایش را برطرف کند.", + "settings.cache.clearing": "در حال پاک کردن...", + "settings.cache.clear": "پاک کردن حافظه پنهان", + "settings.formats.excel.name": "Excel", + "settings.formats.word.name": "Word", + "settings.formats.powerpoint.name": "PowerPoint" +} diff --git a/frontend/src/lib/i18n/messages/fa/translate.json b/frontend/src/lib/i18n/messages/fa/translate.json new file mode 100644 index 0000000..cb7216e --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/translate.json @@ -0,0 +1,92 @@ +{ + "translate.mode.label": "Mode de traduction", + "translate.mode.classic": "Classique", + "translate.mode.classicDesc": "Rapide", + "translate.mode.proLlm": "Pro LLM", + "translate.mode.proLlmDesc": "Contextuel", + "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", + "translate.mode.upgradeLink": "Passer à Pro", + "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", + "translate.glossary.title": "واژه‌نامه", + "translate.glossary.select": "انتخاب واژه‌نامه", + "translate.glossary.none": "هیچکدام", + "translate.glossary.terms": "واژه", + "translate.glossary.proOnly": "ارتقا به Pro برای استفاده از واژه‌نامه", + "translate.glossary.myGlossaries": "واژه‌نامه‌های من", + "translate.glossary.fromTemplate": "ایجاد از قالب", + "translate.glossary.noGlossaryForPair": "واژه‌نامه‌ای برای", + "translate.glossary.noGlossaries": "واژه‌نامه‌ای نیست", + "translate.glossary.loading": "در حال بارگذاری...", + "translate.glossary.classicMode": "موتور خنثی بدون واژه‌نامه (فقط هوش مصنوعی)", + "translate.glossary.selectPlaceholder": "واژه‌نامه‌ای انتخاب کنید...", + "translate.glossary.multilingual": "چندزبانه", + "translate.glossary.noGlossaryAvailable": "واژه‌نامه‌ای در دسترس نیست", + "translate.glossary.filterByLang": "فیلتر بر اساس زبان", + "translate.glossary.active": "فعال", + "translate.glossary.inactive": "غیرفعال", + "translate.glossary.availableTemplates": "قالب‌های موجود", + "translate.glossary.importing": "در حال وارد کردن...", + "translate.glossary.imported": "(وارد شده)", + "translate.glossary.noGlossaryForSource": "واژه‌نامه یا قالبی برای زبان مبدأ وجود ندارد", + "translate.glossary.createGlossary": "ایجاد واژه‌نامه", + "translate.glossary.showAll": "نمایش همه واژه‌نامه‌ها", + "translate.glossary.activePreview": "پیش‌نمایش تطبیق‌های فعال:", + "translate.glossary.total": "مجموع", + "translate.glossary.moreTerms": "واژه‌های بیشتر", + "translate.glossary.noTerms": "واژه‌ای در این واژه‌نامه وجود ندارد.", + "translate.glossary.sourceTerm": "واژه مبدأ", + "translate.glossary.translation": "ترجمه", + "translate.glossary.addTerm": "افزودن واژه", + "translate.glossary.disabledMode": "موتور خنثی بدون واژه‌نامه اعمال شده", + "translate.glossary.addTermError": "خطا در افزودن واژه", + "translate.glossary.networkError": "خطای شبکه", + "translate.glossary.importFailed": "وارد کردن ناموفق ({status})", + "translate.glossary.helpText": "واژه‌نامه ترجمه دقیق واژه‌ها را اجباری می‌کند. واژه‌نامه‌ای انتخاب کنید که زبان مبدأ آن با زبان اصلی سند شما مطابقت داشته باشد.", + "translate.glossary.sourceWarning": "هشدار: این واژه‌نامه از زبان مبدأ استفاده می‌کند", + "translate.glossary.sourceWarningBut": "اما سند شما پیکربندی شده به", + "translate.glossary.targetWarning": "عدم سازگاری هدف: این واژه‌نامه برای ترجمه به", + "translate.glossary.targetWarningBut": "اما هدف سند شما", + "translate.glossary.targetWarningEnd": "واژه‌ها ممکن است مرتبط نباشند.", + "translate.header.processing": "در حال پردازش", + "translate.header.aiActive": "تحلیل هوش مصنوعی فعال", + "translate.header.aiActiveDesc": "چیدمان شما توسط موتور زمینه‌ای ما حفظ می‌شود.", + "translate.header.completed": "تکمیل شد", + "translate.header.completedTitle": "ترجمه تکمیل شد", + "translate.header.proSpace": "فضای Pro", + "translate.header.translateDoc": "ترجمه یک سند", + "translate.header.translateDocDesc": "چیدمان اصلی را با موتور ترجمه فوق‌دقیق ما حفظ کنید.", + "translate.upload.nativeFormat": "قالب بومی", + "translate.fileType.word": "Word (.docx)", + "translate.fileType.excel": "Excel (.xlsx)", + "translate.fileType.slides": "اسلایدها (.pptx)", + "translate.fileType.pdf": "PDF (.pdf)", + "translate.startTranslation": "شروع ترجمه", + "translate.submit": "در حال ارسال…", + "translate.chooseTargetLang": "لطفاً یک زبان مقصد انتخاب کنید", + "translate.pleaseLoadFile": "لطفاً ابتدا یک فایل بارگذاری کنید", + "translate.contextEngineActive": "موتور زمینه‌ای فعال", + "translate.phase1": "مرحله 1: مقداردهی اولیه", + "translate.phase2": "مرحله 2: بازسازی زمینه‌ای", + "translate.stat.segments": "قطعه‌ها", + "translate.stat.precision": "دقت", + "translate.stat.speedLabel": "سرعت", + "translate.stat.turbo": "توربو", + "translate.stat.time": "زمان", + "translate.complete.masterQuality": "✓ کیفیت عالی", + "translate.download": "بارگیری", + "translate.newTranslation": "+ ترجمه جدید", + "translate.failedTitle": "خطای ترجمه", + "translate.retry": "تلاش مجدد", + "translate.uploadAnother": "بارگذاری فایل دیگر", + "translate.monitor": "مانیتور هوش مصنوعی", + "translate.summary": "خلاصه", + "translate.cancelProcess": "⟳ لغو فرآیند", + "translate.layoutIntegrity": "یکپارچگی چیدمان", + "translate.secureHundred": "100% امن", + "translate.okHundred": "100% OK", + "translate.preserveLayout": "حفظ چیدمان", + "translate.preserveLayoutDesc": "حفظ چیدمان", + "translate.textOnly": "فقط متن", + "translate.textOnlyDesc": "ترجمه سریع فقط متن", + "translate.unavailableStandard": "در حالت استاندارد موجود نیست (فقط AI)" +} diff --git a/frontend/src/lib/i18n/messages/fa/translateComplete.json b/frontend/src/lib/i18n/messages/fa/translateComplete.json new file mode 100644 index 0000000..81d5a78 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fa/translateComplete.json @@ -0,0 +1,6 @@ +{ + "translateComplete.highQuality": "کیفیت بالا", + "translateComplete.segments": "قطعه‌ها", + "translateComplete.characters": "نویسه‌ها", + "translateComplete.confidence": "اعتماد" +} diff --git a/frontend/src/lib/i18n/messages/fr/admin.json b/frontend/src/lib/i18n/messages/fr/admin.json new file mode 100644 index 0000000..0d3f492 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/admin.json @@ -0,0 +1,48 @@ +{ + "admin.login.title": "Administration", + "admin.login.required": "Connexion requise", + "admin.login.password": "Mot de passe administrateur", + "admin.login.connecting": "Connexion...", + "admin.login.access": "Accéder au panneau admin", + "admin.login.restricted": "Accès réservé aux administrateurs", + "admin.layout.checking": "Vérification de l'authentification...", + "admin.dashboard.title": "Dashboard Admin", + "admin.dashboard.subtitle": "Panneau de contrôle administrateur", + "admin.dashboard.refresh": "Actualiser", + "admin.dashboard.refreshTooltip": "Actualiser les données du dashboard", + "admin.dashboard.config": "Configuration système", + "admin.dashboard.maxFileSize": "Taille max fichier :", + "admin.dashboard.translationService": "Service de traduction :", + "admin.dashboard.formats": "Formats :", + "admin.nav.dashboard": "Dashboard", + "admin.nav.users": "Utilisateurs", + "admin.nav.pricing": "Tarifs & Stripe", + "admin.nav.providers": "Fournisseurs", + "admin.nav.system": "Système", + "admin.nav.logs": "Logs", + "admin.users.title": "Gestion des Utilisateurs", + "admin.users.subtitle": "Visualiser et gérer les comptes utilisateurs", + "admin.users.planUpdated": "Plan mis à jour", + "admin.users.planChanged": "Le plan a été changé vers \\\"{plan}\\\" avec succès.", + "admin.users.unknownError": "Erreur inconnue", + "admin.users.error": "Erreur", + "admin.users.planUpdateError": "Impossible de mettre à jour le plan : {message}", + "admin.users.noKeys": "Aucune clé", + "admin.users.noKeysDesc": "Cet utilisateur n'a pas de clés API actives.", + "admin.users.keysRevoked": "Clés révoquées", + "admin.users.keysRevokedDesc": "{count} clé(s) API révoquée(s) avec succès.", + "admin.users.revokeError": "Impossible de révoquer les clés : {message}", + "admin.users.retry": "Réessayer", + "admin.system.title": "Système", + "admin.system.subtitle": "Surveiller l'état du système et gérer les ressources", + "admin.system.quotas": "Quotas de traduction", + "admin.system.resetQuotas": "Réinitialiser les quotas mensuels", + "admin.system.resetting": "Réinitialisation...", + "admin.system.reset": "Réinitialiser", + "admin.system.allOperational": "Tous les systèmes opérationnels", + "admin.system.issuesDetected": "Problèmes système détectés", + "admin.system.waitingData": "En attente de données...", + "admin.system.purging": "Purge...", + "admin.system.clean": "Nettoyer", + "admin.system.purge": "Purger" +} diff --git a/frontend/src/lib/i18n/messages/fr/apiKeys.json b/frontend/src/lib/i18n/messages/fr/apiKeys.json new file mode 100644 index 0000000..5fd7eb7 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/apiKeys.json @@ -0,0 +1,72 @@ +{ + "apiKeys.webhook.title": "Intégration Webhook", + "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", + "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", + "apiKeys.webhook.codeParam": "webhook_url", + "apiKeys.title": "Clés API", + "apiKeys.subtitle": "Gérez vos clés API pour l'accès programmatique à l'API de traduction.", + "apiKeys.loading": "Chargement...", + "apiKeys.sectionTitle": "API & Automatisation", + "apiKeys.sectionDesc": "Générez et gérez vos clés API pour les workflows d'automatisation", + "apiKeys.keysUsed": "{total} sur {max} clés utilisées", + "apiKeys.maxReached": "Nombre maximum de clés atteint. Révoquez une clé pour en générer une nouvelle.", + "apiKeys.canGenerate": "Vous pouvez générer {count} clé supplémentaire", + "apiKeys.canGeneratePlural": "Vous pouvez générer {count} clés supplémentaires", + "apiKeys.generateNew": "Générer une nouvelle clé", + "apiKeys.keyRevoked": "Clé révoquée", + "apiKeys.keyRevokedDesc": "La clé API a été révoquée avec succès.", + "apiKeys.keyNotFound": "Clé introuvable", + "apiKeys.keyNotFoundDesc": "La clé API n'existe plus. Elle a peut-être déjà été révoquée.", + "apiKeys.error": "Erreur", + "apiKeys.revokeError": "Impossible de révoquer la clé API. Veuillez réessayer.", + "apiKeys.limitReached": "Limite atteinte", + "apiKeys.limitReachedDesc": "Vous avez atteint le maximum de 10 clés API. Révoquez une clé existante pour en générer une nouvelle.", + "apiKeys.proRequired": "Fonctionnalité Pro requise", + "apiKeys.proRequiredDesc": "Les clés API sont une fonctionnalité Pro. Veuillez mettre à niveau votre compte.", + "apiKeys.generateError": "Impossible de générer la clé API. Veuillez réessayer.", + "apiKeys.upgrade.title": "Clés API", + "apiKeys.upgrade.subtitle": "Automatisez vos traductions avec l'accès API", + "apiKeys.upgrade.feat1": "Générez des clés API illimitées", + "apiKeys.upgrade.feat2": "Automatisez la traduction de documents", + "apiKeys.upgrade.feat3": "Notifications webhook", + "apiKeys.upgrade.feat4": "Modes de traduction IA", + "apiKeys.upgrade.proFeature": "Les clés API sont une fonctionnalité {pro}. Passez à un forfait supérieur pour débloquer l'automatisation API.", + "apiKeys.upgrade.pro": "Pro", + "apiKeys.upgrade.cta": "Passer à Pro", + "apiKeys.dialog.maxTitle": "Nombre maximum de clés atteint", + "apiKeys.dialog.maxDesc": "Vous avez atteint le maximum de 10 clés API. Veuillez révoquer une clé existante avant d'en générer une nouvelle.", + "apiKeys.dialog.close": "Fermer", + "apiKeys.dialog.generated": "Clé API générée !", + "apiKeys.dialog.generatedDesc": "Votre nouvelle clé API a été créée. Copiez-la maintenant — elle ne sera plus affichée.", + "apiKeys.dialog.important": "Important :", + "apiKeys.dialog.importantDesc": "C'est la seule fois où vous verrez cette clé. Conservez-la en toute sécurité.", + "apiKeys.dialog.apiKey": "Clé API", + "apiKeys.dialog.name": "Nom :", + "apiKeys.dialog.done": "Terminé", + "apiKeys.dialog.copied": "J'ai copié la clé", + "apiKeys.dialog.generateTitle": "Générer une nouvelle clé API", + "apiKeys.dialog.generateDesc": "Créez une nouvelle clé API pour l'accès programmatique à l'API de traduction.", + "apiKeys.dialog.keyName": "Nom de la clé (facultatif)", + "apiKeys.dialog.keyNamePlaceholder": "ex : Production, Staging", + "apiKeys.dialog.keyNameHint": "Un nom descriptif pour vous aider à identifier cette clé plus tard.", + "apiKeys.dialog.nameTooLong": "Le nom ne doit pas dépasser {max} caractères", + "apiKeys.dialog.nameInvalid": "Le nom ne peut contenir que des lettres, chiffres, espaces, tirets et tirets bas", + "apiKeys.dialog.cancel": "Annuler", + "apiKeys.dialog.generating": "Génération...", + "apiKeys.dialog.generate": "Générer la clé", + "apiKeys.table.name": "Nom", + "apiKeys.table.prefix": "Préfixe", + "apiKeys.table.created": "Créée", + "apiKeys.table.lastUsed": "Dernière utilisation", + "apiKeys.table.never": "Jamais", + "apiKeys.table.actions": "Actions", + "apiKeys.table.revoke": "Révoquer", + "apiKeys.table.copyPrefix": "Copier le préfixe de la clé", + "apiKeys.table.revokeKey": "Révoquer la clé", + "apiKeys.revokeDialog.title": "Révoquer la clé API", + "apiKeys.revokeDialog.desc": "Êtes-vous sûr de vouloir révoquer la clé « {name} » ? Cette action est irréversible.", + "apiKeys.revokeDialog.confirm": "Oui, révoquer", + "apiKeys.revokeDialog.cancel": "Annuler", + "apiKeys.noKeysGenerated": "Aucune clé générée", + "apiKeys.copied": "Copié !" +} diff --git a/frontend/src/lib/i18n/messages/fr/auth.json b/frontend/src/lib/i18n/messages/fr/auth.json new file mode 100644 index 0000000..b300370 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/auth.json @@ -0,0 +1,3 @@ +{ + "auth.brandName": "Wordly" +} diff --git a/frontend/src/lib/i18n/messages/fr/checkout.json b/frontend/src/lib/i18n/messages/fr/checkout.json new file mode 100644 index 0000000..4c679f0 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/checkout.json @@ -0,0 +1,12 @@ +{ + "checkout.activating": "Activation en cours…", + "checkout.activatingDesc": "Nous mettons à jour votre abonnement, veuillez patienter.", + "checkout.paymentConfirmed": "Paiement confirmé !", + "checkout.subscriptionActivated": "Abonnement activé !", + "checkout.planActivated": "Forfait {plan} activé !", + "checkout.redirectingToProfile": "Redirection vers votre profil…", + "checkout.paymentReceived": "Paiement reçu", + "checkout.redirecting": "Redirection…", + "checkout.syncError": "Erreur de synchronisation", + "checkout.networkError": "Erreur réseau. Votre paiement est confirmé — rechargez votre profil." +} diff --git a/frontend/src/lib/i18n/messages/fr/common.json b/frontend/src/lib/i18n/messages/fr/common.json new file mode 100644 index 0000000..ab4bd48 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/common.json @@ -0,0 +1,4 @@ +{ + "common.loading": "Chargement...", + "common.backToHome": "Retour à l'accueil" +} diff --git a/frontend/src/lib/i18n/messages/fr/context.json b/frontend/src/lib/i18n/messages/fr/context.json new file mode 100644 index 0000000..e673092 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/context.json @@ -0,0 +1,25 @@ +{ + "context.proTitle": "Fonctionnalité Pro", + "context.proDesc": "Le contexte et les glossaires professionnels sont disponibles avec les forfaits Pro, Business et Enterprise. Ils permettent d'obtenir des traductions plus précises grâce à des instructions et un vocabulaire spécifiques à votre domaine.", + "context.viewPlans": "Voir les forfaits", + "context.title": "Contexte & Glossaire", + "context.subtitle": "Améliorez la qualité de traduction avec des instructions et un vocabulaire spécifiques à votre domaine.", + "context.presets.title": "Glossaires professionnels", + "context.presets.desc": "Chargez un glossaire complet avec instructions et terminologie spécialisée", + "context.instructions.title": "Instructions de contexte", + "context.instructions.desc": "Instructions que l'IA suivra pendant la traduction", + "context.instructions.placeholder": "Ex : Vous traduisez des documents techniques HVAC. Utilisez une terminologie d'ingénierie précise...", + "context.glossary.title": "Glossaire technique", + "context.glossary.desc": "Format : source=cible (un par ligne). Les glossaires chargés via preset sont modifiables.", + "context.glossary.terms": "termes dans le glossaire", + "context.clearAll": "Tout effacer", + "context.saving": "Enregistrement...", + "context.save": "Enregistrer", + "context.presets.createGlossary": "Créer le glossaire", + "context.presets.created": "Glossaire créé", + "context.presets.createdDesc": "Le glossaire \\\"{name}\\\" a été créé avec {count} termes.", + "context.presets.hint": "Cliquez sur un preset pour créer un glossaire avec des termes spécifiques au domaine. Gérez vos glossaires dans la section Glossaires.", + "context.glossary.manage": "Gérer les glossaires", + "context.saved": "Enregistré", + "context.savedDesc": "Vos instructions de contexte ont été enregistrées." +} diff --git a/frontend/src/lib/i18n/messages/fr/cookieConsent.json b/frontend/src/lib/i18n/messages/fr/cookieConsent.json new file mode 100644 index 0000000..70247bf --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/cookieConsent.json @@ -0,0 +1,7 @@ +{ + "cookieConsent.title": "Cookies sur Wordly", + "cookieConsent.description": "Nous utilisons des cookies strictement nécessaires au fonctionnement du service (session, sécurité, langue). Avec votre accord, nous pouvons aussi utiliser des cookies optionnels pour mesurer l'audience et améliorer le produit.", + "cookieConsent.acceptAll": "Tout accepter", + "cookieConsent.essentialOnly": "Nécessaires uniquement", + "cookieConsent.learnMore": "En savoir plus" +} diff --git a/frontend/src/lib/i18n/messages/fr/dashboard.json b/frontend/src/lib/i18n/messages/fr/dashboard.json new file mode 100644 index 0000000..62b151f --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/dashboard.json @@ -0,0 +1,115 @@ +{ + "dashboard.nav.translate": "Traduire", + "dashboard.nav.profile": "Mon Profil", + "dashboard.nav.settings": "Paramètres", + "dashboard.nav.context": "Contexte", + "dashboard.nav.services": "Services", + "dashboard.nav.apiKeys": "Clés API", + "dashboard.nav.glossaries": "Glossaires & Contexte", + "dashboard.header.title": "Dashboard", + "dashboard.header.subtitle": "Gérez vos traductions", + "dashboard.header.toggleMenu": "Menu", + "dashboard.header.profileTitle": "Mon profil", + "dashboard.sidebar.theme": "Thème", + "dashboard.sidebar.signOut": "Déconnexion", + "dashboard.sidebar.backHome": "Retour à l'accueil", + "dashboard.sidebar.upgradeToPro": "Passer Pro →", + "dashboard.translate.pageTitle": "Traduire un document", + "dashboard.translate.pageSubtitle": "Importez un fichier et choisissez la langue cible", + "dashboard.translate.errorNotificationTitle": "Erreur", + "dashboard.translate.dropzone.uploadAria": "Zone de dépôt de fichier", + "dashboard.translate.dropzone.title": "Glissez-déposez votre fichier ici", + "dashboard.translate.dropzone.subtitle": "ou cliquez pour sélectionner (DOCX, XLSX, PPTX, PDF)", + "dashboard.translate.dropzone.replaceFile": "Remplacer le fichier", + "dashboard.translate.language.source": "Langue source", + "dashboard.translate.language.target": "Langue cible", + "dashboard.translate.language.loading": "Chargement des langues…", + "dashboard.translate.language.autoDetect": "Auto-détection", + "dashboard.translate.language.selectPlaceholder": "Sélectionner…", + "dashboard.translate.language.loadErrorPrefix": "Erreur de chargement des langues", + "dashboard.translate.provider.loading": "Chargement des fournisseurs…", + "dashboard.translate.provider.noneConfigured": "Aucun fournisseur configuré", + "dashboard.translate.provider.modelTitle": "Modèle", + "dashboard.translate.provider.sectionTitle": "Fournisseur", + "dashboard.translate.provider.llmDivider": "IA · Context-Aware", + "dashboard.translate.provider.llmDividerPro": "IA · Context-Aware (Pro)", + "dashboard.translate.provider.upgrade": "Passer Pro", + "dashboard.translate.provider.upgradeSuffix": "pour débloquer la traduction IA", + "dashboard.translate.provider.tabStandard": "Standard", + "dashboard.translate.provider.tabLLM": "Multi-Modèles IA", + "dashboard.translate.translateImages": "Traduire les images", + "dashboard.translate.translateImagesDesc": "Extraire et traduire le texte des images (vision requise)", + "dashboard.translate.trust.zeroRetention": "Rétention zéro", + "dashboard.translate.trust.deletedAfter": "Fichiers supprimés après traitement", + "dashboard.translate.actions.uploading": "Chargement…", + "dashboard.translate.actions.translate": "Traduire", + "dashboard.translate.actions.filePrefix": "Fichier : ", + "dashboard.translate.actions.cancel": "Annuler", + "dashboard.translate.actions.tryAgain": "Réessayer", + "dashboard.translate.steps.uploading": "Chargement du fichier…", + "dashboard.translate.steps.starting": "Démarrage de la traduction…", + "dashboard.translate.complete.title": "Traduction terminée !", + "dashboard.translate.complete.descNamed": "Votre fichier {name} a été traduit avec succès.", + "dashboard.translate.complete.descGeneric": "Votre fichier a été traduit avec succès.", + "dashboard.translate.complete.downloading": "Téléchargement…", + "dashboard.translate.complete.download": "Télécharger", + "dashboard.translate.complete.newTranslation": "Nouvelle traduction", + "dashboard.translate.complete.toastOkTitle": "Succès", + "dashboard.translate.complete.toastOkDesc": "{name} a été téléchargé avec succès.", + "dashboard.translate.complete.toastFailTitle": "Échec", + "dashboard.translate.complete.toastFailDesc": "La traduction a échoué. Veuillez réessayer.", + "dashboard.translate.sourceDocument": "Document source", + "dashboard.translate.configuration": "Configuration", + "dashboard.translate.translating": "Traduction en cours", + "dashboard.translate.liveMonitor": "Moniteur en direct", + "dashboard.translate.summary": "Résumé", + "dashboard.translate.engine": "Moteur", + "dashboard.translate.confidence": "Confiance", + "dashboard.translate.cancel": "Annuler", + "dashboard.translate.segments": "Segments", + "dashboard.translate.characters": "Caractères", + "dashboard.translate.elapsed": "Écoulé", + "dashboard.translate.segPerMin": "Seg/min", + "dashboard.translate.highQuality": "Haute qualité", + "dashboard.translate.quality": "Qualité", + "dashboard.translate.completed": "Traduction terminée", + "dashboard.translate.replace": "Remplacer", + "dashboard.translate.pdfMode.title": "Mode de traduction PDF", + "dashboard.translate.pdfMode.preserveLayout": "Préserver la mise en page", + "dashboard.translate.pdfMode.textOnly": "Texte uniquement", + "dashboard.translate.pdfMode.preserveLayoutDesc": "Conserve les images, tableaux et formatage. Idéal pour les PDF simples.", + "dashboard.translate.pdfMode.textOnlyDesc": "Traduit tout le texte parfaitement. Sortie propre, sans problème de mise en page.", + "dashboard.translate.pipeline.upload": "Upload", + "dashboard.translate.pipeline.analyze": "Analyse", + "dashboard.translate.pipeline.translate": "Traduction", + "dashboard.translate.pipeline.rebuild": "Reconstruction", + "dashboard.translate.pipeline.finalize": "Finalisation", + "dashboard.translate.progress.processingFallback": "Traitement en cours…", + "dashboard.translate.progress.connectionLost": "Connexion perdue. Reconnexion…", + "dashboard.translate.progress.failedTitle": "Traduction échouée", + "dashboard.translate.error.unexpected": "Une erreur inattendue est survenue. Réessayez.", + "dashboard.translate.error.noResult": "La traduction n'a produit aucun résultat. Vérifiez que le document contient du texte, puis réessayez ou choisissez un autre moteur.", + "dashboard.translate.error.apiKey": "Clé API invalide ou manquante. Contactez l'administrateur pour configurer les clés.", + "dashboard.translate.error.quota": "Limite d'utilisation atteinte. Réessayez dans quelques minutes ou choisissez un autre moteur.", + "dashboard.translate.error.timeout": "La connexion au service de traduction a expiré. Vérifiez votre réseau et réessayez.", + "dashboard.translate.error.sessionExpired": "La session a expiré. Cliquez sur Réessayer pour relancer la traduction.", + "dashboard.translate.error.empty": "Le document semble vide ou ne contient pas de texte traduisible (PDF image ?).", + "dashboard.translate.error.unsupported": "Format de fichier non supporté ou fichier corrompu.", + "dashboard.translate.error.connection": "Connexion perdue. Vérifiez votre réseau et réessayez.", + "dashboard.translate.error.generic": "Traduction échouée : {detail}", + "dashboard.translate.error.title": "Traduction échouée", + "dashboard.translate.retry": "Réessayer la traduction", + "dashboard.translate.newFile": "Nouveau fichier", + "dashboard.translate.modeAI": "Mode IA", + "dashboard.translate.modeClassic": "Mode Classique", + "dashboard.translate.glossaryLLMHint": "Glossaires disponibles en mode IA", + "dashboard.translate.submitting": "Envoi en cours...", + "dashboard.translate.submit": "Lancer la traduction", + "dashboard.translate.noFile": "Déposez d'abord un fichier", + "dashboard.translate.noTargetLang": "Sélectionnez une langue cible", + "dashboard.topbar.interfaceLabel": "Interface de traduction", + "dashboard.topbar.premiumAccess": "Accès Premium", + "dashboard.checkoutSyncError": "Erreur lors de la synchronisation du paiement.", + "dashboard.networkRefresh": "Erreur réseau. Veuillez rafraîchir la page.", + "dashboard.continueToTranslate": "Continuer vers la traduction" +} diff --git a/frontend/src/lib/i18n/messages/fr/fileUploader.json b/frontend/src/lib/i18n/messages/fr/fileUploader.json new file mode 100644 index 0000000..aa1c2a0 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/fileUploader.json @@ -0,0 +1,31 @@ +{ + "fileUploader.uploadDocument": "Téléverser un document", + "fileUploader.uploadDesc": "Glissez-déposez ou cliquez pour sélectionner un fichier (Excel, Word, PowerPoint)", + "fileUploader.dropHere": "Déposez votre fichier ici…", + "fileUploader.dragAndDrop": "Glissez-déposez votre document ici", + "fileUploader.orClickBrowse": "ou cliquez pour parcourir", + "fileUploader.preview": "Aperçu", + "fileUploader.translationOptions": "Options de traduction", + "fileUploader.configureSettings": "Configurez vos paramètres de traduction", + "fileUploader.targetLanguage": "Langue cible", + "fileUploader.selectLanguage": "Sélectionner une langue", + "fileUploader.translationProvider": "Fournisseur de traduction", + "fileUploader.selectProvider": "Sélectionner un fournisseur", + "fileUploader.advancedOptions": "Options avancées", + "fileUploader.translateImages": "Traduire les images", + "fileUploader.translating": "Traduction…", + "fileUploader.translateDocument": "Traduire le document", + "fileUploader.processing": "Traitement…", + "fileUploader.translationError": "Erreur de traduction", + "fileUploader.translationComplete": "Traduction terminée !", + "fileUploader.translationCompleteDesc": "Votre document a été traduit avec succès tout en préservant la mise en forme.", + "fileUploader.download": "Télécharger le document traduit", + "fileUploader.webgpuUnsupported": "WebGPU n'est pas pris en charge dans ce navigateur. Veuillez utiliser Chrome 113+ ou Edge 113+.", + "fileUploader.webllmNotLoaded": "Modèle WebLLM non chargé. Allez dans Paramètres > Services de traduction pour charger un modèle.", + "fileUploader.extracting": "Extraction des textes du document…", + "fileUploader.noTranslatable": "Aucun texte traduisible trouvé dans le document", + "fileUploader.foundTexts": "{count} textes trouvés à traduire", + "fileUploader.translatingItem": "Traduction {current}/{total} : « {preview} »", + "fileUploader.reconstructing": "Reconstruction du document…", + "fileUploader.translatingLocally": "Traduction locale avec WebLLM…" +} diff --git a/frontend/src/lib/i18n/messages/fr/forgotPassword.json b/frontend/src/lib/i18n/messages/fr/forgotPassword.json new file mode 100644 index 0000000..f86256f --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/forgotPassword.json @@ -0,0 +1,14 @@ +{ + "forgotPassword.enterEmail": "Veuillez entrer votre adresse email", + "forgotPassword.error": "Une erreur s'est produite", + "forgotPassword.title": "Mot de passe oublié", + "forgotPassword.checkEmail": "Vérifiez votre boîte mail", + "forgotPassword.subtitle": "Entrez votre email pour recevoir un lien de réinitialisation", + "forgotPassword.sentMessage": "Si un compte existe avec cette adresse, un email de réinitialisation a été envoyé.", + "forgotPassword.emailLabel": "Adresse email", + "forgotPassword.emailPlaceholder": "vous@exemple.com", + "forgotPassword.sending": "Envoi en cours...", + "forgotPassword.sendLink": "Envoyer le lien de réinitialisation", + "forgotPassword.backToLogin": "Retour à la connexion", + "forgotPassword.loading": "Chargement..." +} diff --git a/frontend/src/lib/i18n/messages/fr/glossaries.json b/frontend/src/lib/i18n/messages/fr/glossaries.json new file mode 100644 index 0000000..0e8de14 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/glossaries.json @@ -0,0 +1,189 @@ +{ + "glossaries.yourGlossaries": "Vos glossaires", + "glossaries.title": "Glossaires & Contexte", + "glossaries.description": "Gérez vos glossaires et instructions de contexte pour des traductions plus précises.", + "glossaries.createNew": "Créer nouveau", + "glossaries.empty": "Aucun glossaire", + "glossaries.emptyDesc": "Créez votre premier glossaire ou chargez un préréglage professionnel ci-dessus", + "glossaries.defineTerms": "termes", + "glossaries.aboutTitle": "À propos des glossaires", + "glossaries.aboutDesc": "Les glossaires vous permettent de définir des traductions exactes pour des termes spécifiques. Lors de la traduction, les termes du glossaire garantissent des traductions cohérentes et précises.", + "glossaries.aboutFormat": "Chaque terme a un mot source et des traductions en plusieurs langues. Sélectionnez un glossaire dans la page de traduction pour l'appliquer.", + "glossaries.toast.created": "Glossaire créé", + "glossaries.toast.createdDesc": "Le glossaire \\\"{name}\\\" a été créé.", + "glossaries.toast.imported": "Glossaire importé", + "glossaries.toast.importedDesc": "Le glossaire \\\"{name}\\\" a été importé.", + "glossaries.toast.updated": "Glossaire mis à jour", + "glossaries.toast.updatedDesc": "Le glossaire \\\"{name}\\\" a été mis à jour.", + "glossaries.toast.deleted": "Glossaire supprimé", + "glossaries.toast.deletedDesc": "Le glossaire a été supprimé.", + "glossaries.toast.error": "Erreur", + "glossaries.toast.errorCreate": "Impossible de créer le glossaire", + "glossaries.toast.errorImport": "Impossible d'importer le glossaire", + "glossaries.toast.errorUpdate": "Impossible de mettre à jour le glossaire", + "glossaries.toast.errorDelete": "Impossible de supprimer le glossaire", + "glossaries.dialog.title": "Nouveau glossaire", + "glossaries.dialog.description": "Créez un glossaire pour vos traductions", + "glossaries.dialog.nameLabel": "Nom", + "glossaries.dialog.namePlaceholder": "Mon glossaire", + "glossaries.dialog.tabTemplates": "Modèles", + "glossaries.dialog.tabFile": "Fichier", + "glossaries.dialog.tabManual": "Manuel", + "glossaries.dialog.cancel": "Annuler", + "glossaries.dialog.creating": "Création…", + "glossaries.dialog.importing": "Import…", + "glossaries.dialog.importBtn": "Importer", + "glossaries.dialog.selectPrompt": "Sélectionner", + "glossaries.dialog.createBtn": "Créer", + "glossaries.dialog.createEmpty": "Créer vide", + "glossaries.dialog.terms": "termes", + "glossaries.dialog.templatesDesc": "Choisissez un modèle prédéfini", + "glossaries.dialog.templatesEmpty": "Aucun modèle disponible", + "glossaries.dialog.dropTitle": "Glissez un fichier CSV ici", + "glossaries.dialog.dropOr": "ou", + "glossaries.dialog.dropFormats": "CSV, TSV, TXT", + "glossaries.termEditor.addTerm": "Ajouter un terme", + "glossaries.termEditor.maxReached": "Maximum {max} termes par glossaire atteint.", + "glossaries.dialog.formatTitle": "Format", + "glossaries.dialog.formatDesc": "source,target (un par ligne)", + "glossaries.dialog.formatNote": "Première ligne ignorée si en-tête détecté", + "glossaries.dialog.errorFormat": "Format non supporté", + "glossaries.dialog.errorSize": "Fichier trop volumineux", + "glossaries.dialog.errorEmpty": "Fichier vide", + "glossaries.dialog.errorRead": "Erreur de lecture", + "glossaries.dialog.parsing": "Analyse…", + "glossaries.dialog.termsImported": "termes importés", + "glossaries.dialog.changeFile": "Changer le fichier", + "glossaries.dialog.retry": "Réessayer", + "glossaries.edit.title": "Modifier le glossaire", + "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", + "glossaries.edit.nameLabel": "Nom du glossaire", + "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", + "glossaries.edit.sourceLang": "Langue source", + "glossaries.edit.targetLang": "Langue cible", + "glossaries.edit.termsLabel": "Termes ({count} valides)", + "glossaries.edit.exportCsv": "Exporter CSV", + "glossaries.edit.importCsv": "Importer CSV", + "glossaries.edit.cancel": "Annuler", + "glossaries.edit.saving": "Enregistrement...", + "glossaries.edit.saveChanges": "Enregistrer les modifications", + "glossaries.edit.importFailedTitle": "Échec de l'importation", + "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", + "glossaries.edit.importSuccessTitle": "Importation réussie", + "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", + "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", + "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", + "glossaries.delete.title": "Supprimer le glossaire", + "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", + "glossaries.delete.warning": "Cette action est irréversible", + "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", + "glossaries.delete.cancel": "Annuler", + "glossaries.delete.deleting": "Suppression...", + "glossaries.delete.deleteBtn": "Supprimer", + "glossaries.upgrade.title": "Glossaires", + "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", + "glossaries.upgrade.feature1": "Créez plusieurs glossaires", + "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", + "glossaries.upgrade.feature3": "Importez/exportez via CSV", + "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", + "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", + "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", + "glossaries.upgrade.proLabel": "Pro", + "glossaries.upgrade.upgradeBtn": "Passer à Pro", + "glossaries.loading": "Chargement...", + "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", + "glossaries.howItWorks.step1Title": "Configurez ici", + "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", + "glossaries.howItWorks.step2Title": "Activez dans Traduire", + "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", + "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", + "glossaries.howItWorks.goToTranslate": "Aller à Traduire", + "glossaries.status.unsaved": "Non enregistré", + "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", + "glossaries.status.inactive": "Inactif", + "glossaries.instructions.whatForBold": "À quoi ça sert ?", + "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", + "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", + "glossaries.instructions.charCount": "{count} caractères", + "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", + "glossaries.instructions.clearAll": "Tout effacer", + "glossaries.instructions.saving": "Enregistrement…", + "glossaries.instructions.saved": "Enregistré", + "glossaries.presets.whatForBold": "À quoi ça sert ?", + "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", + "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", + "glossaries.presets.creating": "Création…", + "glossaries.presets.alreadyImported": "Déjà importé", + "glossaries.presets.it.title": "IT / Logiciel", + "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", + "glossaries.presets.legal.title": "Juridique / Contrats", + "glossaries.presets.legal.desc": "Droit des affaires, contentieux", + "glossaries.presets.medical.title": "Médical / Santé", + "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", + "glossaries.presets.finance.title": "Finance / Comptabilité", + "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", + "glossaries.presets.marketing.title": "Marketing / Publicité", + "glossaries.presets.marketing.desc": "Digital, branding, analytics", + "glossaries.presets.hr.title": "RH / Ressources Humaines", + "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", + "glossaries.presets.scientific.title": "Scientifique / Recherche", + "glossaries.presets.scientific.desc": "Publications, thèses, articles", + "glossaries.presets.ecommerce.title": "E-commerce / Vente", + "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", + "glossaries.grid.title": "Vos", + "glossaries.grid.titleHighlight": "glossaires", + "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", + "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", + "glossaries.grid.activeTranslation": "Traduction active :", + "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", + "glossaries.badge.compatible": "Compatible", + "glossaries.badge.otherTarget": "Autre cible", + "glossaries.card.editTerms": "Modifier les termes", + "glossaries.card.created": "Créé", + "glossaries.card.term": "terme", + "glossaries.card.delete": "Supprimer", + "glossaries.grid.searchPlaceholder": "Rechercher un glossaire…", + "glossaries.grid.noResults": "Aucun résultat pour cette recherche.", + "glossaries.detail.backToList": "Retour aux glossaires", + "glossaries.detail.save": "Enregistrer", + "glossaries.detail.savedTitle": "Enregistré", + "glossaries.detail.savedDesc": "Le glossaire a été mis à jour.", + "glossaries.detail.settingsTitle": "Paramètres", + "glossaries.detail.sourceLang": "Langue source", + "glossaries.detail.targetLang": "Langue cible", + "glossaries.detail.termsTitle": "Termes", + "glossaries.detail.terms": "termes", + "glossaries.detail.searchTerms": "Filtrer…", + "glossaries.detail.noTerms": "Aucun terme pour l'instant.", + "glossaries.detail.addFirstTerm": "Ajouter le premier terme", + "glossaries.detail.addTerm": "Ajouter un terme", + "glossaries.detail.maxReached": "Limite maximale atteinte", + "glossaries.detail.source": "Source", + "glossaries.detail.target": "Cible", + "glossaries.detail.sourcePlaceholder": "terme source", + "glossaries.detail.targetPlaceholder": "terme cible", + "glossaries.detail.csvTitle": "CSV", + "glossaries.detail.csvDesc": "Exportez vos termes en CSV ou importez-en de nouveaux (remplace la liste actuelle).", + "glossaries.detail.export": "Exporter", + "glossaries.detail.import": "Importer", + "glossaries.detail.dangerTitle": "Zone danger", + "glossaries.detail.dangerDesc": "La suppression est définitive. Tous les termes associés seront perdus.", + "glossaries.detail.deleteGlossary": "Supprimer ce glossaire", + "glossaries.detail.confirmDelete": "Confirmer la suppression ?", + "glossaries.detail.confirm": "Confirmer", + "glossaries.detail.cancel": "Annuler", + "glossaries.detail.sourceLangNote": "'La source originale est en francais. Pour les autres langues, on lit le champ translations du terme (si disponible).'", + "glossaries.detail.sourceLocked": "fixé", + "glossaries.detail.sourceLockedNote": "Les templates ne stockent la source qu'en français. Le multilingue source est sur la roadmap.", + "glossaries.detail.targetLangNote": "Choisissez une langue pour voir les traductions correspondantes, ou « Multilingue » pour la valeur par défaut.", + "glossaries.detail.notFoundTitle": "Glossaire introuvable", + "glossaries.detail.notFoundDesc": "Ce glossaire n'existe pas ou vous n'y avez pas accès.", + "glossaries.detail.maxTermsTitle": "Limite atteinte", + "glossaries.detail.maxTermsDesc": "Maximum {max} termes par glossaire.", + "glossaries.detail.importEmptyTitle": "Fichier vide", + "glossaries.detail.importEmptyDesc": "Aucun terme détecté dans ce fichier.", + "glossaries.detail.importedTitle": "Importé", + "glossaries.detail.importedDesc": "{count} termes importés.", + "glossaries.detail.importErrorTitle": "Erreur de lecture", + "glossaries.detail.importErrorDesc": "Impossible de lire le fichier." +} diff --git a/frontend/src/lib/i18n/messages/fr/index.ts b/frontend/src/lib/i18n/messages/fr/index.ts new file mode 100644 index 0000000..e665dfe --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/index.ts @@ -0,0 +1,60 @@ +// Auto-generated by scripts/generate_i18n_index.py +// Merges all namespace JSON files for locale "fr". + +import admin from "./admin.json"; +import apiKeys from "./apiKeys.json"; +import auth from "./auth.json"; +import checkout from "./checkout.json"; +import common from "./common.json"; +import context from "./context.json"; +import cookieConsent from "./cookieConsent.json"; +import dashboard from "./dashboard.json"; +import fileUploader from "./fileUploader.json"; +import forgotPassword from "./forgotPassword.json"; +import glossaries from "./glossaries.json"; +import landing from "./landing.json"; +import langSelector from "./langSelector.json"; +import layout from "./layout.json"; +import login from "./login.json"; +import memento from "./memento.json"; +import pricing from "./pricing.json"; +import profile from "./profile.json"; +import providerSelector from "./providerSelector.json"; +import providerTheme from "./providerTheme.json"; +import register from "./register.json"; +import resetPassword from "./resetPassword.json"; +import services from "./services.json"; +import settings from "./settings.json"; +import translate from "./translate.json"; +import translateComplete from "./translateComplete.json"; + +const messages: Record = { + ...admin, + ...apiKeys, + ...auth, + ...checkout, + ...common, + ...context, + ...cookieConsent, + ...dashboard, + ...fileUploader, + ...forgotPassword, + ...glossaries, + ...landing, + ...langSelector, + ...layout, + ...login, + ...memento, + ...pricing, + ...profile, + ...providerSelector, + ...providerTheme, + ...register, + ...resetPassword, + ...services, + ...settings, + ...translate, + ...translateComplete, +}; + +export default messages; diff --git a/frontend/src/lib/i18n/messages/fr/landing.json b/frontend/src/lib/i18n/messages/fr/landing.json new file mode 100644 index 0000000..f39c201 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/landing.json @@ -0,0 +1,152 @@ +{ + "landing.nav.why": "Pourquoi nous ?", + "landing.nav.formats": "Formats", + "landing.nav.pricing": "Tarification", + "landing.nav.login": "Connexion", + "landing.nav.startFree": "Essai gratuit", + "landing.hero.tag": "IA Documentaire Professionnelle", + "landing.hero.titleLine1": "Traduisez vos documents.", + "landing.hero.titleLine2": "Mise en forme parfaite.", + "landing.hero.description": "Le seul traducteur qui préserve les SmartArt, graphiques, tables des matières, formes, en-têtes et pieds de page — exactement tels qu'ils étaient.", + "landing.hero.ctaMain": "Essai gratuit — 2 docs/mois", + "landing.hero.ctaSec": "Voir les offres", + "landing.hero.deleted": "Fichiers supprimés après 60 min", + "landing.hero.noHidden": "Pas de prix cachés", + "landing.hero.preview": "Aperçu avant paiement", + "landing.hero.formattedOk": "Formatage OK", + "landing.hero.aiActive": "Traduction IA active", + "landing.steps.title": "Comment ça marche ?", + "landing.steps.subtitle": "Trois étapes. Zéro perte de format.", + "landing.steps.step1.num": "01", + "landing.steps.step1.title": "Déposez votre fichier", + "landing.steps.step1.desc": "Glissez-déposez votre document Excel, Word, PowerPoint ou PDF.", + "landing.steps.step2.num": "02", + "landing.steps.step2.title": "Choisissez la langue", + "landing.steps.step2.desc": "Sélectionnez la langue cible et le moteur de traduction — classique ou IA contextuelle.", + "landing.steps.step3.num": "03", + "landing.steps.step3.title": "Téléchargez le résultat", + "landing.steps.step3.desc": "Récupérez votre document traduit avec un formatage identique à l'original.", + "landing.features.tag": "Moteur de Traduction IA", + "landing.features.title": "La traduction qui comprend votre métier", + "landing.features.description": "Nos modèles IA analysent le contexte, respectent votre terminologie et traduisent même le texte dans vos images.", + "landing.features.context.title": "Contexte métier", + "landing.features.context.desc": "Décrivez votre domaine et obtenez des traductions adaptées, pas génériques.", + "landing.features.glossary.title": "Glossaires métier", + "landing.features.glossary.desc": "Définissez vos termes techniques. CTA restera « Air Handling Unit », jamais « Call To Action ».", + "landing.features.vision.title": "Vision sur images", + "landing.features.vision.desc": "Le texte incrusté dans vos images, diagrammes et graphiques est détecté et traduit.", + "landing.features.demo.source": "Source (FR)", + "landing.features.demo.google": "Google Translate", + "landing.features.demo.ours": "Notre IA", + "landing.layout.title": "Votre mise en forme,", + "landing.layout.title2": "parfaitement préservée", + "landing.layout.subtitle": "Les autres traducteurs détruisent votre mise en page. Pas nous.", + "landing.layout.p1.title": "SmartArt et diagrammes", + "landing.layout.p1.desc": "Organigrammes, flux, hiérarchies — tout traduit à l'identique.", + "landing.layout.p2.title": "Tables des matières", + "landing.layout.p2.desc": "Entrées de TDM, numéros et renvois mis à jour correctement.", + "landing.layout.p3.title": "Graphiques", + "landing.layout.p3.desc": "Titres, étiquettes, légendes et séries — tout est traduit.", + "landing.layout.p4.title": "Formes et zones de texte", + "landing.layout.p4.desc": "Rectangles, blocs arrondis, légendes — localisé partout.", + "landing.layout.p5.title": "En-têtes et pieds de page", + "landing.layout.p5.desc": "En-têtes, pieds de page et notes ne sont jamais oubliés.", + "landing.layout.p6.title": "130+ langues", + "landing.layout.p6.desc": "Google Traduction, DeepL et moteurs IA haute performance.", + "landing.formats.title": "Chaque format,", + "landing.formats.title2": "chaque élément", + "landing.formats.subtitle": "Nous traduisons ce que les autres oublient. Votre entreprise mérite une documentation irréprochable.", + "landing.formats.word.name": "Word", + "landing.formats.word.i1": "Paragraphes et titres", + "landing.formats.word.i2": "Tableaux et graphiques", + "landing.formats.word.i3": "Diagrammes SmartArt", + "landing.formats.word.i4": "Table des matières", + "landing.formats.word.i5": "En-têtes et pieds", + "landing.formats.word.i6": "Formes et zones de texte", + "landing.formats.word.i7": "Notes de bas de page", + "landing.formats.excel.name": "Excel", + "landing.formats.excel.i1": "Valeurs de cellules", + "landing.formats.excel.i2": "Noms de feuilles", + "landing.formats.excel.i3": "Graphiques et étiquettes", + "landing.formats.excel.i4": "En-têtes et pieds", + "landing.formats.excel.i5": "Cellules fusionnées", + "landing.formats.pptx.name": "PowerPoint", + "landing.formats.pptx.i1": "Texte et notes", + "landing.formats.pptx.i2": "Graphiques et diagrammes", + "landing.formats.pptx.i3": "Formes et zones de texte", + "landing.formats.pptx.i4": "Masques de diapositives", + "landing.formats.pptx.i5": "Animations préservées", + "landing.formats.pdf.name": "PDF", + "landing.formats.pdf.i1": "PDF textuels", + "landing.formats.pdf.i2": "Mise en page préservée", + "landing.formats.pdf.i3": "Images conservées", + "landing.formats.pdf.i4": "Tableaux maintenus", + "landing.formats.pdf.i5": "Sortie DOCX ou PDF", + "landing.pricing.title": "Des prix simples et honnêtes", + "landing.pricing.subtitle": "Ce que vous voyez est ce que vous payez. Aucun frais caché.", + "landing.pricing.monthly": "Mensuel", + "landing.pricing.annual": "Annuel", + "landing.pricing.bestValue": "Le plus populaire", + "landing.pricing.month": "/mois", + "landing.pricing.footer": "Le prix affiché est le prix que vous payez. Aucun frais caché après traduction.", + "landing.pricing.starter.name": "Starter", + "landing.pricing.starter.desc": "Pour les particuliers et petits projets", + "landing.pricing.starter.f1": "50 documents / mois", + "landing.pricing.starter.f2": "Jusqu'à 50 pages par doc", + "landing.pricing.starter.f3": "Google Traduction + DeepL", + "landing.pricing.starter.f4": "Fichiers jusqu'à 10 Mo", + "landing.pricing.starter.cta": "Commencer", + "landing.pricing.pro.name": "Pro", + "landing.pricing.pro.desc": "Pour les professionnels exigeants", + "landing.pricing.pro.f1": "200 documents / mois", + "landing.pricing.pro.f2": "Jusqu'à 200 pages par doc", + "landing.pricing.pro.f3": "Traduction par IA", + "landing.pricing.pro.f4": "Google + DeepL inclus", + "landing.pricing.pro.f5": "Glossaires et prompts", + "landing.pricing.pro.f6": "Support prioritaire", + "landing.pricing.pro.cta": "Essayer Pro", + "landing.pricing.business.name": "Business", + "landing.pricing.business.desc": "Pour les équipes avec des besoins élevés", + "landing.pricing.business.f1": "1 000 documents / mois", + "landing.pricing.business.f2": "Jusqu'à 500 pages par doc", + "landing.pricing.business.f3": "IA Premium (Claude)", + "landing.pricing.business.f4": "Tous les fournisseurs + API", + "landing.pricing.business.f5": "Webhooks et automatisation", + "landing.pricing.business.f6": "5 postes d'équipe", + "landing.pricing.business.cta": "Nous contacter", + "landing.pricing.free.name": "Gratuit", + "landing.pricing.free.desc": "Idéal pour découvrir l'application", + "landing.pricing.free.cta": "Choisir ce plan", + "landing.pricing.enterprise.name": "Entreprise", + "landing.pricing.enterprise.desc": "Solutions sur mesure pour les grandes organisations", + "landing.pricing.enterprise.cta": "Nous contacter", + "landing.cta.title": "Commencez à traduire en 30 secondes", + "landing.cta.subtitle": "Aucune carte bancaire requise. Essayez gratuitement dès maintenant et redonnez vie à vos documents multilingues.", + "landing.cta.button": "Créer un compte gratuit", + "landing.cta.secure": "Sécurisé par chiffrement AES-256", + "landing.footer.desc": "Spécialiste de la traduction documentaire intelligente. Nous marions l'art de la mise en page et la science de l'IA contextuelle.", + "landing.footer.product": "Produit", + "landing.footer.resources": "Ressources", + "landing.footer.legal": "Légal", + "landing.footer.rights": "© 2026 Wordly.art — Tous droits réservés.", + "landing.hero.contextEngine": "Traduction détectée : Terme technique de maintenance pour systèmes CVC...", + "landing.hero.liveAnalysis": "Analyse en direct", + "landing.hero.termsDetected": "termes détectés", + "landing.steps.process": "PROCESSUS", + "landing.translate.newProject": "Nouveau projet", + "landing.translate.title": "Traduire un document", + "landing.translate.subtitle": "Importez un fichier et choisissez la langue cible", + "landing.translate.sourceDocument": "Document source", + "landing.translate.configuration": "Configuration", + "landing.translate.sourceLang": "Langue source", + "landing.translate.targetLang": "Langue cible", + "landing.translate.provider": "Fournisseur", + "landing.translate.startTranslation": "Lancer la traduction", + "landing.translate.zeroRetention": "Rétention zéro", + "landing.translate.filesDeleted": "Fichiers supprimés après traitement", + "landing.translate.dropHere": "Glissez-déposez ici", + "landing.translate.supportedFormats": "Fichiers DOCX, XLSX, PPTX ou PDF supportés", + "landing.translate.aiAnalysis": "Analyse IA Active", + "landing.translate.processing": "Traitement en cours", + "landing.translate.preservingLayout": "Votre mise en page est en cours de préservation" +} diff --git a/frontend/src/lib/i18n/messages/fr/langSelector.json b/frontend/src/lib/i18n/messages/fr/langSelector.json new file mode 100644 index 0000000..d6b3ecd --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/langSelector.json @@ -0,0 +1,7 @@ +{ + "langSelector.search": "Rechercher…", + "langSelector.noResults": "Aucun résultat", + "langSelector.source": "Source", + "langSelector.target": "Cible", + "langSelector.swap": "Inverser" +} diff --git a/frontend/src/lib/i18n/messages/fr/layout.json b/frontend/src/lib/i18n/messages/fr/layout.json new file mode 100644 index 0000000..d912e29 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/layout.json @@ -0,0 +1,5 @@ +{ + "layout.nav.apiAccess": "Accès API", + "layout.footer.terms": "CGU", + "layout.footer.privacy": "Confidentialité" +} diff --git a/frontend/src/lib/i18n/messages/fr/login.json b/frontend/src/lib/i18n/messages/fr/login.json new file mode 100644 index 0000000..7066e4f --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/login.json @@ -0,0 +1,18 @@ +{ + "login.errorTitle": "Erreur de connexion", + "login.welcomeBack": "Bienvenue", + "login.signInToContinue": "Connectez-vous pour continuer à traduire", + "login.email": "Email", + "login.emailPlaceholder": "vous@exemple.com", + "login.password": "Mot de passe", + "login.forgotPassword": "Mot de passe oublié ?", + "login.passwordPlaceholder": "••••••••", + "login.signingIn": "Connexion en cours...", + "login.signIn": "Se connecter", + "login.noAccount": "Pas encore de compte ?", + "login.signUpFree": "Créer un compte gratuit", + "login.orContinueWith": "ou continuer avec l'e-mail", + "login.google.connecting": "Connexion…", + "login.google.errorGeneric": "Une erreur est survenue avec la connexion Google.", + "login.google.errorFailed": "La connexion Google a échoué. Veuillez réessayer." +} diff --git a/frontend/src/lib/i18n/messages/fr/memento.json b/frontend/src/lib/i18n/messages/fr/memento.json new file mode 100644 index 0000000..555a528 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/memento.json @@ -0,0 +1,6 @@ +{ + "memento.title": "Découvrez Momento", + "memento.slogan": "Momento n'est pas qu'une simple application de notes. C'est un écosystème intelligent qui connecte, analyse et développe vos idées en temps réel grâce à 6 types d'agents IA et une recherche sémantique de pointe.", + "memento.ctaFree": "Commencer gratuitement", + "memento.ctaMore": "Voir plus" +} diff --git a/frontend/src/lib/i18n/messages/fr/pricing.json b/frontend/src/lib/i18n/messages/fr/pricing.json new file mode 100644 index 0000000..6eb343b --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/pricing.json @@ -0,0 +1,151 @@ +{ + "pricing.nav.back": "Retour", + "pricing.nav.home": "Accueil", + "pricing.nav.mySubscription": "Mon abonnement", + "pricing.header.badge": "Modèles IA mis à jour — Mars 2026", + "pricing.header.title": "Un forfait pour chaque besoin", + "pricing.header.subtitle": "Traduisez vos documents Word, Excel et PowerPoint en conservant la mise en page originale. Sans jamais saisir de clé API.", + "pricing.billing.monthly": "Mensuel", + "pricing.billing.yearly": "Annuel", + "pricing.plans.free.name": "Gratuit", + "pricing.plans.starter.name": "Starter", + "pricing.plans.pro.name": "Pro", + "pricing.plans.business.name": "Business", + "pricing.plans.enterprise.name": "Entreprise", + "pricing.plans.free.description": "Parfait pour découvrir l'application", + "pricing.plans.starter.description": "Pour les particuliers et petits projets", + "pricing.plans.pro.description": "Pour les professionnels et équipes en croissance", + "pricing.plans.business.description": "Pour les équipes et organisations", + "pricing.plans.enterprise.description": "Solutions sur mesure pour grandes organisations", + "pricing.plans.pro.highlight": "Le plus populaire", + "pricing.plans.pro.badge": "POPULAIRE", + "pricing.plans.enterprise.badge": "SUR DEVIS", + "pricing.plans.free.feat1": "5 documents / mois", + "pricing.plans.free.feat2": "Jusqu'à 15 pages par document", + "pricing.plans.free.feat3": "Google Traduction inclus", + "pricing.plans.free.feat4": "Toutes les langues (130+)", + "pricing.plans.free.feat5": "Support communautaire", + "pricing.plans.starter.feat1": "50 documents / mois", + "pricing.plans.starter.feat2": "Jusqu'à 50 pages par document", + "pricing.plans.starter.feat3": "Google Traduction + DeepL", + "pricing.plans.starter.feat4": "Fichiers jusqu'à 10 Mo", + "pricing.plans.starter.feat5": "Support par e-mail", + "pricing.plans.starter.feat6": "Historique 30 jours", + "pricing.plans.pro.feat1": "200 documents / mois", + "pricing.plans.pro.feat2": "Jusqu'à 200 pages par document", + "pricing.plans.pro.feat3": "Traduction IA Essentielle", + "pricing.plans.pro.feat4": "Google Traduction + DeepL", + "pricing.plans.pro.feat5": "Fichiers jusqu'à 25 Mo", + "pricing.plans.pro.feat6": "Glossaires personnalisés", + "pricing.plans.pro.feat7": "Support prioritaire", + "pricing.plans.pro.feat8": "Historique 90 jours", + "pricing.plans.business.feat1": "1 000 documents / mois", + "pricing.plans.business.feat2": "Jusqu'à 500 pages par document", + "pricing.plans.business.feat3": "IA Essentielle + Premium (Claude Haiku)", + "pricing.plans.business.feat4": "Tous les fournisseurs de traduction", + "pricing.plans.business.feat5": "Fichiers jusqu'à 50 Mo", + "pricing.plans.business.feat6": "Accès API (10 000 appels/mois)", + "pricing.plans.business.feat7": "Webhooks de notification", + "pricing.plans.business.feat8": "Support dédié", + "pricing.plans.business.feat9": "Historique 1 an", + "pricing.plans.business.feat10": "Analytiques avancées", + "pricing.plans.enterprise.feat1": "Documents illimités", + "pricing.plans.enterprise.feat2": "Tous les modèles IA (GPT-5, Claude Opus 4.6…)", + "pricing.plans.enterprise.feat3": "Déploiement on-premise ou cloud dédié", + "pricing.plans.enterprise.feat4": "SLA 99,9 % garanti", + "pricing.plans.enterprise.feat5": "Support 24/7 dédié", + "pricing.plans.enterprise.feat6": "Marque blanche (white-label)", + "pricing.plans.enterprise.feat7": "Équipes illimitées", + "pricing.plans.enterprise.feat8": "Intégrations sur mesure", + "pricing.card.onRequest": "Sur devis", + "pricing.card.free": "Gratuit", + "pricing.card.perMonth": "/mois", + "pricing.card.billedYearly": "Facturé {price} € / an", + "pricing.card.documents": "Documents", + "pricing.card.pagesMax": "Pages max", + "pricing.card.aiTranslation": "Traduction IA", + "pricing.card.unlimited": "Illimité", + "pricing.card.perMonthStat": "/ mois", + "pricing.card.perDoc": "p / doc", + "pricing.card.aiEssential": "Essentielle", + "pricing.card.aiEssentialPremium": "Essentielle + Premium", + "pricing.card.aiCustom": "Sur mesure", + "pricing.card.myPlan": "Mon forfait", + "pricing.card.managePlan": "Gérer mon forfait", + "pricing.card.startFree": "Commencer gratuitement", + "pricing.card.contactUs": "Nous contacter", + "pricing.card.choosePlan": "Choisir ce forfait", + "pricing.card.processing": "Traitement…", + "pricing.comparison.title": "Comparaison détaillée", + "pricing.comparison.subtitle": "Tout ce qui est inclus dans chaque forfait", + "pricing.comparison.feature": "Fonctionnalité", + "pricing.comparison.docsPerMonth": "Documents / mois", + "pricing.comparison.pagesMaxPerDoc": "Pages max / document", + "pricing.comparison.maxFileSize": "Taille max fichier", + "pricing.comparison.googleTranslation": "Google Traduction", + "pricing.comparison.deepl": "DeepL", + "pricing.comparison.aiEssential": "Traduction IA Essentielle", + "pricing.comparison.aiPremium": "Traduction IA Premium", + "pricing.comparison.apiAccess": "Accès API", + "pricing.comparison.priorityProcessing": "Traitement prioritaire", + "pricing.comparison.support": "Support", + "pricing.comparison.support.community": "Communauté", + "pricing.comparison.support.email": "E-mail", + "pricing.comparison.support.priority": "Prioritaire", + "pricing.comparison.support.dedicated": "Dédié", + "pricing.comparison.mb": "Mo", + "pricing.credits.title": "Crédits supplémentaires", + "pricing.credits.subtitle": "Besoin de plus ? Achetez des crédits à l'unité, sans abonnement.", + "pricing.credits.perPage": "1 crédit = 1 page traduite.", + "pricing.credits.bestValue": "Le meilleur rapport", + "pricing.credits.unit": "crédits", + "pricing.credits.centsPerCredit": "cts / crédit", + "pricing.credits.buy": "Acheter", + "pricing.trust.encryption.title": "Chiffrement de bout en bout", + "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 au repos", + "pricing.trust.languages.title": "130+ langues", + "pricing.trust.languages.sub": "Dont arabe, persan, hébreu (RTL)", + "pricing.trust.parallel.title": "Traitement parallèle", + "pricing.trust.parallel.sub": "IA multi-thread ultra-rapide", + "pricing.trust.availability.title": "Disponible 24/7", + "pricing.trust.availability.sub": "Uptime garanti 99,9 %", + "pricing.aiModels.title": "Nos modèles IA — Mars 2026", + "pricing.aiModels.essential.title": "Traduction IA Essentielle", + "pricing.aiModels.essential.plan": "Forfait Pro", + "pricing.aiModels.essential.descPrefix": "Basée sur", + "pricing.aiModels.essential.descSuffix": "— le modèle IA le plus rentable de 2026. Qualité comparable aux modèles frontier à une fraction du coût.", + "pricing.aiModels.essential.modelName": "notre modèle IA Essentiel", + "pricing.aiModels.essential.context": "163K tokens de contexte", + "pricing.aiModels.essential.value": "Excellent rapport qualité/prix", + "pricing.aiModels.premium.title": "Traduction IA Premium", + "pricing.aiModels.premium.plan": "Forfait Business", + "pricing.aiModels.premium.descPrefix": "Basée sur", + "pricing.aiModels.premium.descSuffix": "d'Anthropic — précis sur les documents juridiques, médicaux et techniques complexes.", + "pricing.aiModels.premium.context": "200K tokens de contexte", + "pricing.aiModels.premium.precision": "Meilleure précision", + "pricing.faq.title": "Questions fréquentes", + "pricing.faq.q1": "Puis-je changer de forfait à tout moment ?", + "pricing.faq.a1": "Oui. Le passage à un forfait supérieur est immédiat et proratisé. La rétrogradation prend effet à la fin de la période en cours.", + "pricing.faq.q2": "Qu'est-ce que la « Traduction IA Essentielle » ?", + "pricing.faq.a2": "C'est notre moteur IA. Il comprend le contexte de vos documents, préserve la mise en page et gère les termes techniques bien mieux qu'une traduction classique.", + "pricing.faq.q3": "Quelle est la différence entre IA Essentielle et IA Premium ?", + "pricing.faq.a3": "L'IA Essentielle utilise un modèle optimisé (excellent rapport qualité/prix). L'IA Premium utilise Claude Sonnet 4.6 d'Anthropic, plus précis sur les documents juridiques, médicaux et techniques complexes.", + "pricing.faq.q4": "Mes documents sont-ils conservés après traduction ?", + "pricing.faq.a4": "Les fichiers traduits sont disponibles selon votre forfait (30 jours Starter, 90 jours Pro, 1 an Business). Ils sont chiffrés au repos et en transit.", + "pricing.faq.q5": "Que se passe-t-il si je dépasse mon quota mensuel ?", + "pricing.faq.a5": "Vous pouvez acheter des crédits supplémentaires à l'unité, ou upgrader votre forfait. Vous êtes notifié à 80 % d'utilisation.", + "pricing.faq.q6": "Y a-t-il une version d'essai gratuite des forfaits payants ?", + "pricing.faq.a6": "Le forfait Gratuit est permanent et sans carte bancaire. Pour les forfaits Pro et Business, contactez-nous pour un accès d'essai de 14 jours.", + "pricing.faq.q7": "Quels formats de fichiers sont supportés ?", + "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx), et bientôt PDF. Tous les plans supportent les mêmes formats.", + "pricing.cta.title": "Prêt à commencer ?", + "pricing.cta.subtitle": "Commencez gratuitement, sans carte bancaire. Passez à un forfait supérieur quand vous en avez besoin.", + "pricing.cta.createAccount": "Créer un compte gratuit", + "pricing.cta.login": "Se connecter", + "pricing.toast.demo": "Mode démo — Stripe n'est pas encore configuré. En production, vous seriez redirigé vers le paiement pour activer le forfait {planId}.", + "pricing.toast.networkError": "Erreur réseau. Veuillez réessayer.", + "pricing.toast.paymentError": "Erreur lors de la création du paiement.", + "pricing.dashboard": "Tableau de bord", + "pricing.okSymbol": "✓", + "pricing.errSymbol": "✕" +} diff --git a/frontend/src/lib/i18n/messages/fr/profile.json b/frontend/src/lib/i18n/messages/fr/profile.json new file mode 100644 index 0000000..a44bbe4 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/profile.json @@ -0,0 +1,58 @@ +{ + "profile.header.title": "Mon Profil", + "profile.header.subtitle": "Gérez votre compte et vos préférences.", + "profile.tabs.account": "Compte", + "profile.tabs.subscription": "Abonnement", + "profile.tabs.preferences": "Préférences", + "profile.account.user": "Utilisateur", + "profile.account.memberSince": "Membre depuis", + "profile.plan.label": "Forfait", + "profile.plan.free": "Gratuit", + "profile.plan.starter": "Starter", + "profile.plan.pro": "Pro", + "profile.plan.business": "Business", + "profile.plan.enterprise": "Enterprise", + "profile.plan.pricePerMonth": "{price} €/mois", + "profile.subscription.canceling": "Annulation en cours", + "profile.subscription.active": "Actif", + "profile.subscription.unknown": "Inconnu", + "profile.subscription.accessUntil": "Accès jusqu'au", + "profile.subscription.renewalOn": "Renouvellement le", + "profile.subscription.upgradePlan": "Passer à un forfait payant", + "profile.subscription.changePlan": "Changer de forfait", + "profile.subscription.manageBilling": "Gérer la facturation", + "profile.subscription.billingUnavailable": "Portail de facturation non disponible.", + "profile.subscription.billingError": "Erreur lors de l'accès au portail.", + "profile.subscription.cancelSuccess": "Abonnement annulé. Vous conservez l'accès jusqu'à la fin de la période.", + "profile.subscription.cancelError": "Erreur lors de l'annulation.", + "profile.subscription.networkError": "Erreur réseau.", + "profile.usage.title": "Utilisation ce mois-ci", + "profile.usage.resetOn": "Reset le", + "profile.usage.documents": "Documents", + "profile.usage.pages": "Pages", + "profile.usage.extraCredits": "crédit supplémentaire", + "profile.usage.extraCreditsPlural": "crédits supplémentaires", + "profile.usage.quotaReached": "Quota atteint", + "profile.usage.quotaReachedDesc": "Passez à un forfait supérieur pour continuer.", + "profile.usage.unlockMore": "Débloquez plus de traductions avec un forfait payant.", + "profile.usage.viewPlans": "Voir les forfaits", + "profile.usage.includedInPlan": "Inclus dans votre forfait", + "profile.danger.title": "Zone danger", + "profile.danger.description": "L'annulation prend effet à la fin de votre période en cours. Vous conservez l'accès jusqu'à cette date.", + "profile.danger.confirm": "Êtes-vous sûr(e) ? Cette action ne peut pas être annulée.", + "profile.danger.confirmCancel": "Confirmer l'annulation", + "profile.danger.cancelSubscription": "Annuler mon abonnement", + "profile.danger.keep": "Non, garder", + "profile.prefs.interfaceLang": "Langue de l'interface", + "profile.prefs.interfaceLangDesc": "La langue est détectée automatiquement selon votre navigateur. Vous pouvez la changer manuellement.", + "profile.prefs.defaultTargetLang": "Langue cible par défaut", + "profile.prefs.selectLanguage": "Sélectionner une langue", + "profile.prefs.defaultTargetLangDesc": "Cette langue sera pré-sélectionnée lors de vos traductions.", + "profile.prefs.save": "Enregistrer", + "profile.prefs.theme": "Thème", + "profile.prefs.themeDesc": "Choisissez l'apparence de l'interface", + "profile.prefs.cache": "Cache", + "profile.prefs.cacheDesc": "Effacer le cache local peut résoudre certains problèmes d'affichage.", + "profile.prefs.clearing": "Effacement...", + "profile.prefs.clearCache": "Effacer le cache" +} diff --git a/frontend/src/lib/i18n/messages/fr/providerSelector.json b/frontend/src/lib/i18n/messages/fr/providerSelector.json new file mode 100644 index 0000000..fd4865e --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/providerSelector.json @@ -0,0 +1,7 @@ +{ + "providerSelector.noClassic": "Aucun traducteur standard disponible.", + "providerSelector.noLlm": "Aucun modèle IA configuré.", + "providerSelector.costOne": "Coût : 1 crédit par page", + "providerSelector.costFive": "Coût : 5 crédits par page (Facteur Premium)", + "providerSelector.unlockContextual": "Débloquez la traduction contextuelle haut de gamme pour vos documents entiers." +} diff --git a/frontend/src/lib/i18n/messages/fr/providerTheme.json b/frontend/src/lib/i18n/messages/fr/providerTheme.json new file mode 100644 index 0000000..deb032e --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/providerTheme.json @@ -0,0 +1,29 @@ +{ + "providerTheme.deepseek.badge": "Essentielle", + "providerTheme.deepseek.subBadge": "Technique & Éco", + "providerTheme.deepseek.desc": "Traduction ultra-précise et économique, idéale pour les documents techniques et le code.", + "providerTheme.openai.badge": "Premium", + "providerTheme.openai.subBadge": "Haute Fidélité", + "providerTheme.openai.desc": "Le standard mondial de l'IA. Cohérence textuelle maximale et respect strict du style.", + "providerTheme.minimax.badge": "Avancée", + "providerTheme.minimax.subBadge": "Performance", + "providerTheme.minimax.desc": "Vitesse d'exécution incroyable et excellente compréhension des structures complexes.", + "providerTheme.openrouter.badge": "Express", + "providerTheme.openrouter.subBadge": "Multi-Modèles", + "providerTheme.openrouter.desc": "Accès unifié aux meilleurs modèles open-source optimisés pour la traduction.", + "providerTheme.openrouter_premium.badge": "Ultra", + "providerTheme.openrouter_premium.subBadge": "Maximum Context", + "providerTheme.openrouter_premium.desc": "Traduction assistée par les modèles de pointe (GPT-4o, Claude Sonnet 4.6) pour documents longs.", + "providerTheme.zai.badge": "Spécialisée", + "providerTheme.zai.subBadge": "Finance & Droit", + "providerTheme.zai.desc": "Modèle affiné pour les terminologies métiers exigeantes (juridique, finance).", + "providerTheme.default.badge": "Moderne", + "providerTheme.default.subBadge": "Raisonnement IA", + "providerTheme.default.desc": "Traduction par grand modèle linguistique (LLM) avec analyse sémantique avancée.", + "providerTheme.classic.google.label": "Google Traduction", + "providerTheme.classic.google.desc": "Traduction ultra-rapide couvrant plus de 130 langues. Recommandé pour les flux généraux.", + "providerTheme.classic.deepl.label": "DeepL Pro", + "providerTheme.classic.deepl.desc": "Traduction haute précision réputée pour sa fluidité et ses formulations naturelles.", + "providerTheme.classic.google_cloud.label": "Google Cloud API", + "providerTheme.classic.google_cloud.desc": "Moteur cloud professionnel optimisé pour le traitement de gros volumes de documents." +} diff --git a/frontend/src/lib/i18n/messages/fr/register.json b/frontend/src/lib/i18n/messages/fr/register.json new file mode 100644 index 0000000..76339db --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/register.json @@ -0,0 +1,29 @@ +{ + "register.title": "Créer un compte", + "register.subtitle": "Commencez à traduire gratuitement", + "register.error.failed": "L'inscription a échoué", + "register.name.label": "Nom", + "register.name.placeholder": "Votre nom", + "register.name.error": "Le nom doit contenir au moins 2 caractères", + "register.email.label": "Adresse email", + "register.email.placeholder": "vous@exemple.com", + "register.email.error": "Adresse email invalide", + "register.password.label": "Mot de passe", + "register.password.error": "Le mot de passe doit contenir au moins 8 caractères, une majuscule, une minuscule et un chiffre", + "register.password.show": "Afficher le mot de passe", + "register.password.hide": "Masquer le mot de passe", + "register.password.strengthLabel": "Force :", + "register.password.strength.weak": "Faible", + "register.password.strength.medium": "Moyen", + "register.password.strength.strong": "Fort", + "register.confirmPassword.label": "Confirmer le mot de passe", + "register.confirmPassword.error": "Les mots de passe ne correspondent pas", + "register.confirmPassword.show": "Afficher", + "register.confirmPassword.hide": "Masquer", + "register.submit.creating": "Création du compte...", + "register.submit.create": "Créer mon compte", + "register.hasAccount": "Vous avez déjà un compte ?", + "register.login": "Se connecter", + "register.terms.prefix": "En créant un compte, vous acceptez notre", + "register.terms.link": "utilisation du service" +} diff --git a/frontend/src/lib/i18n/messages/fr/resetPassword.json b/frontend/src/lib/i18n/messages/fr/resetPassword.json new file mode 100644 index 0000000..926a1f0 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/resetPassword.json @@ -0,0 +1,22 @@ +{ + "resetPassword.passwordRequirements": "Le mot de passe doit contenir au moins 8 caractères, une majuscule, une minuscule et un chiffre", + "resetPassword.passwordMismatch": "Les mots de passe ne correspondent pas", + "resetPassword.tokenMissing": "Token manquant. Veuillez utiliser le lien reçu par email.", + "resetPassword.error": "Une erreur s'est produite", + "resetPassword.invalidLink": "Lien invalide", + "resetPassword.invalidLinkMessage": "Ce lien de réinitialisation est invalide. Veuillez redemander un nouveau lien.", + "resetPassword.requestNewLink": "Redemander un lien", + "resetPassword.successTitle": "Mot de passe réinitialisé", + "resetPassword.newPasswordTitle": "Nouveau mot de passe", + "resetPassword.successSubtitle": "Vous allez être redirigé vers la connexion", + "resetPassword.subtitle": "Définissez votre nouveau mot de passe", + "resetPassword.successMessage": "Votre mot de passe a été réinitialisé avec succès. Vous allez être redirigé vers la page de connexion.", + "resetPassword.newPassword": "Nouveau mot de passe", + "resetPassword.showPassword": "Afficher le mot de passe", + "resetPassword.hidePassword": "Masquer le mot de passe", + "resetPassword.confirmPassword": "Confirmer le mot de passe", + "resetPassword.resetting": "Réinitialisation...", + "resetPassword.resetPassword": "Réinitialiser le mot de passe", + "resetPassword.backToLogin": "Retour à la connexion", + "resetPassword.loading": "Chargement..." +} diff --git a/frontend/src/lib/i18n/messages/fr/services.json b/frontend/src/lib/i18n/messages/fr/services.json new file mode 100644 index 0000000..9898475 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/services.json @@ -0,0 +1,14 @@ +{ + "services.title": "Fournisseurs de traduction", + "services.subtitle": "Les fournisseurs sont configurés par l'administrateur. Vous pouvez voir ceux actuellement disponibles pour votre compte.", + "services.loading": "Chargement des fournisseurs...", + "services.noProviders": "Aucun fournisseur n'est actuellement configuré. Contactez votre administrateur.", + "services.classic": "Traduction classique", + "services.llmPro": "IA · Contextuelle (Pro)", + "services.available": "Disponible", + "services.model": "Modèle", + "services.adminOnly.title": "La configuration des fournisseurs est réservée à l'administrateur", + "services.adminOnly.desc": "Les clés API, la sélection de modèle et l'activation des fournisseurs sont gérées exclusivement par l'administrateur. Vous n'avez jamais besoin de saisir de clé API.", + "services.fallback.google.label": "Google Traduction", + "services.fallback.google.desc": "Traduction rapide, 130+ langues" +} diff --git a/frontend/src/lib/i18n/messages/fr/settings.json b/frontend/src/lib/i18n/messages/fr/settings.json new file mode 100644 index 0000000..f997f03 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/settings.json @@ -0,0 +1,20 @@ +{ + "settings.title": "Paramètres", + "settings.subtitle": "Configuration générale de l'application", + "settings.formats.title": "Formats supportés", + "settings.formats.subtitle": "Types de documents que vous pouvez traduire", + "settings.formats.formulas": "Formules", + "settings.formats.styles": "Styles", + "settings.formats.images": "Images", + "settings.formats.headers": "En-têtes", + "settings.formats.tables": "Tableaux", + "settings.formats.slides": "Slides", + "settings.formats.notes": "Notes", + "settings.cache.title": "Cache", + "settings.cache.desc": "Effacer le cache local peut résoudre certains problèmes d'affichage.", + "settings.cache.clearing": "Effacement...", + "settings.cache.clear": "Effacer le cache", + "settings.formats.excel.name": "Excel", + "settings.formats.word.name": "Word", + "settings.formats.powerpoint.name": "PowerPoint" +} diff --git a/frontend/src/lib/i18n/messages/fr/translate.json b/frontend/src/lib/i18n/messages/fr/translate.json new file mode 100644 index 0000000..88430a7 --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/translate.json @@ -0,0 +1,93 @@ +{ + "translate.glossary.selectGlossary": "Sélectionner un glossaire...", + "translate.mode.label": "Mode de traduction", + "translate.mode.classic": "Classique", + "translate.mode.classicDesc": "Rapide", + "translate.mode.proLlm": "Pro LLM", + "translate.mode.proLlmDesc": "Contextuel", + "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", + "translate.mode.upgradeLink": "Passer à Pro", + "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", + "translate.glossary.title": "Glossaire", + "translate.glossary.select": "Sélectionner un glossaire", + "translate.glossary.none": "Aucun", + "translate.glossary.terms": "termes", + "translate.glossary.proOnly": "Passez à Pro pour utiliser les glossaires", + "translate.glossary.myGlossaries": "Mes glossaires", + "translate.glossary.fromTemplate": "Créer depuis un template", + "translate.glossary.noGlossaryForPair": "Aucun glossaire pour", + "translate.glossary.noGlossaries": "Aucun glossaire", + "translate.glossary.loading": "Chargement...", + "translate.glossary.classicMode": "Moteur neutre sans glossaire (IA uniquement)", + "translate.glossary.selectPlaceholder": "Sélectionner un glossaire...", + "translate.glossary.multilingual": "MULTILINGUE", + "translate.glossary.noGlossaryAvailable": "Aucun glossaire disponible", + "translate.glossary.filterByLang": "Filtrer par langue", + "translate.glossary.active": "Actif", + "translate.glossary.inactive": "Inactif", + "translate.glossary.availableTemplates": "Modèles disponibles", + "translate.glossary.importing": "Importation...", + "translate.glossary.imported": "(Importé)", + "translate.glossary.noGlossaryForSource": "Aucun glossaire ni modèle pour la langue source", + "translate.glossary.createGlossary": "Créer un glossaire", + "translate.glossary.showAll": "Afficher tous les glossaires", + "translate.glossary.activePreview": "Aperçu des correspondances actives :", + "translate.glossary.total": "au total", + "translate.glossary.moreTerms": "autres termes", + "translate.glossary.noTerms": "Aucun terme dans ce glossaire.", + "translate.glossary.sourceTerm": "Terme Source", + "translate.glossary.translation": "Traduction", + "translate.glossary.addTerm": "Ajouter le terme", + "translate.glossary.disabledMode": "Moteur neutre sans glossaire appliqué", + "translate.glossary.addTermError": "Erreur lors de l'ajout du terme", + "translate.glossary.networkError": "Erreur réseau", + "translate.glossary.importFailed": "Échec de l'importation ({status})", + "translate.glossary.helpText": "Le glossaire force la traduction de termes précis. Choisissez un glossaire dont la langue source correspond à la langue d'origine de votre document.", + "translate.glossary.sourceWarning": "Attention : Ce glossaire utilise la langue source", + "translate.glossary.sourceWarningBut": "mais votre document est configuré en", + "translate.glossary.targetWarning": "Incompatibilité de cible : Ce glossaire est prévu pour traduire vers", + "translate.glossary.targetWarningBut": "mais votre document cible", + "translate.glossary.targetWarningEnd": "Les termes risquent de ne pas être pertinents.", + "translate.header.processing": "Traitement en cours", + "translate.header.aiActive": "Analyse IA active", + "translate.header.aiActiveDesc": "Votre mise en page est en cours de préservation par notre moteur contextuel.", + "translate.header.completed": "Complété", + "translate.header.completedTitle": "Traduction terminée", + "translate.header.proSpace": "Espace Pro", + "translate.header.translateDoc": "Traduire un document", + "translate.header.translateDocDesc": "Conservez la mise en page d'origine grâce au moteur de traduction ultra-haute fidélité.", + "translate.upload.nativeFormat": "Format natif", + "translate.fileType.word": "Word (.docx)", + "translate.fileType.excel": "Excel (.xlsx)", + "translate.fileType.slides": "Slides (.pptx)", + "translate.fileType.pdf": "PDF (.pdf)", + "translate.startTranslation": "Lancer la traduction", + "translate.submit": "Soumission…", + "translate.chooseTargetLang": "Veuillez choisir une langue cible", + "translate.pleaseLoadFile": "Veuillez charger un fichier d'abord", + "translate.contextEngineActive": "Moteur contextuel actif", + "translate.phase1": "Phase 1 : Initialisation", + "translate.phase2": "Phase 2 : Reconstruction contextuelle", + "translate.stat.segments": "segments", + "translate.stat.precision": "précision", + "translate.stat.speedLabel": "vitesse", + "translate.stat.turbo": "Turbo", + "translate.stat.time": "temps", + "translate.complete.masterQuality": "✓ Qualité Maître", + "translate.download": "Télécharger", + "translate.newTranslation": "+ Nouvelle traduction", + "translate.failedTitle": "Erreur lors de la traduction", + "translate.retry": "Réessayer", + "translate.uploadAnother": "Téléverser un autre fichier", + "translate.monitor": "Moniteur IA", + "translate.summary": "Récapitulatif", + "translate.cancelProcess": "⟳ Annuler le processus", + "translate.layoutIntegrity": "Intégrité Layout", + "translate.secureHundred": "100% SÉCURISÉ", + "translate.okHundred": "100% OK", + "translate.preserveLayout": "Conserver la mise en page", + "translate.preserveLayoutDesc": "Conserver la mise en page", + "translate.textOnly": "Texte brut", + "translate.textOnlyDesc": "Traduction rapide du texte uniquement", + "translate.unavailableStandard": "Indisponible en mode Standard (IA uniquement)" +} diff --git a/frontend/src/lib/i18n/messages/fr/translateComplete.json b/frontend/src/lib/i18n/messages/fr/translateComplete.json new file mode 100644 index 0000000..ae3ff2c --- /dev/null +++ b/frontend/src/lib/i18n/messages/fr/translateComplete.json @@ -0,0 +1,6 @@ +{ + "translateComplete.highQuality": "Haute qualité", + "translateComplete.segments": "Segments", + "translateComplete.characters": "Caractères", + "translateComplete.confidence": "Confiance" +} diff --git a/frontend/src/lib/i18n/messages/index.json b/frontend/src/lib/i18n/messages/index.json new file mode 100644 index 0000000..b8c82f7 --- /dev/null +++ b/frontend/src/lib/i18n/messages/index.json @@ -0,0 +1,405 @@ +{ + "locales": [ + "ar", + "de", + "en", + "es", + "fa", + "fr", + "it", + "ja", + "ko", + "nl", + "pt", + "ru", + "zh" + ], + "namespaces": [ + "admin", + "apiKeys", + "auth", + "checkout", + "common", + "context", + "cookieConsent", + "dashboard", + "fileUploader", + "forgotPassword", + "glossaries", + "landing", + "langSelector", + "layout", + "login", + "memento", + "pricing", + "profile", + "providerSelector", + "providerTheme", + "register", + "resetPassword", + "services", + "settings", + "translate", + "translateComplete" + ], + "manifest": { + "ar": [ + "admin", + "apiKeys", + "auth", + "checkout", + "common", + "context", + "cookieConsent", + "dashboard", + "fileUploader", + "glossaries", + "landing", + "langSelector", + "layout", + "login", + "memento", + "pricing", + "profile", + "providerSelector", + "providerTheme", + "register", + "services", + "settings", + "translate", + "translateComplete" + ], + "de": [ + "admin", + "apiKeys", + "auth", + "checkout", + "common", + "context", + "cookieConsent", + "dashboard", + "fileUploader", + "forgotPassword", + "glossaries", + "landing", + "langSelector", + "layout", + "login", + "memento", + "pricing", + "profile", + "providerSelector", + "providerTheme", + "register", + "resetPassword", + "services", + "settings", + "translate", + "translateComplete" + ], + "en": [ + "admin", + "apiKeys", + "auth", + "checkout", + "common", + "context", + "cookieConsent", + "dashboard", + "fileUploader", + "forgotPassword", + "glossaries", + "landing", + "langSelector", + "layout", + "login", + "memento", + "pricing", + "profile", + "providerSelector", + "providerTheme", + "register", + "resetPassword", + "services", + "settings", + "translate", + "translateComplete" + ], + "es": [ + "admin", + "apiKeys", + "auth", + "checkout", + "common", + "context", + "cookieConsent", + "dashboard", + "fileUploader", + "forgotPassword", + "glossaries", + "landing", + "langSelector", + "layout", + "login", + "memento", + "pricing", + "profile", + "providerSelector", + "providerTheme", + "register", + "resetPassword", + "services", + "settings", + "translate", + "translateComplete" + ], + "fa": [ + "admin", + "apiKeys", + "auth", + "checkout", + "common", + "context", + "cookieConsent", + "dashboard", + "fileUploader", + "glossaries", + "landing", + "langSelector", + "layout", + "login", + "memento", + "pricing", + "profile", + "providerSelector", + "providerTheme", + "register", + "services", + "settings", + "translate", + "translateComplete" + ], + "fr": [ + "admin", + "apiKeys", + "auth", + "checkout", + "common", + "context", + "cookieConsent", + "dashboard", + "fileUploader", + "forgotPassword", + "glossaries", + "landing", + "langSelector", + "layout", + "login", + "memento", + "pricing", + "profile", + "providerSelector", + "providerTheme", + "register", + "resetPassword", + "services", + "settings", + "translate", + "translateComplete" + ], + "it": [ + "admin", + "apiKeys", + "auth", + "checkout", + "common", + "context", + "cookieConsent", + "dashboard", + "fileUploader", + "forgotPassword", + "glossaries", + "landing", + "langSelector", + "layout", + "login", + "memento", + "pricing", + "profile", + "providerSelector", + "providerTheme", + "register", + "resetPassword", + "services", + "settings", + "translate", + "translateComplete" + ], + "ja": [ + "admin", + "apiKeys", + "auth", + "checkout", + "common", + "context", + "cookieConsent", + "dashboard", + "fileUploader", + "forgotPassword", + "glossaries", + "landing", + "langSelector", + "layout", + "login", + "memento", + "pricing", + "profile", + "providerSelector", + "providerTheme", + "register", + "resetPassword", + "services", + "settings", + "translate", + "translateComplete" + ], + "ko": [ + "admin", + "apiKeys", + "auth", + "checkout", + "common", + "context", + "cookieConsent", + "dashboard", + "fileUploader", + "forgotPassword", + "glossaries", + "landing", + "langSelector", + "layout", + "login", + "memento", + "pricing", + "profile", + "providerSelector", + "providerTheme", + "register", + "resetPassword", + "services", + "settings", + "translate", + "translateComplete" + ], + "nl": [ + "admin", + "apiKeys", + "auth", + "checkout", + "common", + "context", + "cookieConsent", + "dashboard", + "fileUploader", + "forgotPassword", + "glossaries", + "landing", + "langSelector", + "layout", + "login", + "memento", + "pricing", + "profile", + "providerSelector", + "providerTheme", + "register", + "resetPassword", + "services", + "settings", + "translate", + "translateComplete" + ], + "pt": [ + "admin", + "apiKeys", + "auth", + "checkout", + "common", + "context", + "cookieConsent", + "dashboard", + "fileUploader", + "forgotPassword", + "glossaries", + "landing", + "langSelector", + "layout", + "login", + "memento", + "pricing", + "profile", + "providerSelector", + "providerTheme", + "register", + "resetPassword", + "services", + "settings", + "translate", + "translateComplete" + ], + "ru": [ + "admin", + "apiKeys", + "auth", + "checkout", + "common", + "context", + "cookieConsent", + "dashboard", + "fileUploader", + "forgotPassword", + "glossaries", + "landing", + "langSelector", + "layout", + "login", + "memento", + "pricing", + "profile", + "providerSelector", + "providerTheme", + "register", + "resetPassword", + "services", + "settings", + "translate", + "translateComplete" + ], + "zh": [ + "admin", + "apiKeys", + "auth", + "checkout", + "common", + "context", + "cookieConsent", + "dashboard", + "fileUploader", + "glossaries", + "landing", + "langSelector", + "layout", + "login", + "memento", + "pricing", + "profile", + "providerSelector", + "providerTheme", + "register", + "services", + "settings", + "translate", + "translateComplete" + ] + } +} diff --git a/frontend/src/lib/i18n/messages/it/admin.json b/frontend/src/lib/i18n/messages/it/admin.json new file mode 100644 index 0000000..9c805a4 --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/admin.json @@ -0,0 +1,48 @@ +{ + "admin.login.title": "Amministrazione", + "admin.login.required": "Accesso richiesto", + "admin.login.password": "Password amministratore", + "admin.login.connecting": "Connessione...", + "admin.login.access": "Accedi al pannello admin", + "admin.login.restricted": "Riservato agli amministratori", + "admin.layout.checking": "Verifica dell'autenticazione...", + "admin.dashboard.title": "Dashboard Admin", + "admin.dashboard.subtitle": "Pannello di controllo amministratore", + "admin.dashboard.refresh": "Aggiorna", + "admin.dashboard.refreshTooltip": "Aggiorna dati dashboard", + "admin.dashboard.config": "Configurazione di sistema", + "admin.dashboard.maxFileSize": "Dimensione max file:", + "admin.dashboard.translationService": "Servizio di traduzione:", + "admin.dashboard.formats": "Formati:", + "admin.nav.dashboard": "Dashboard", + "admin.nav.users": "Utenti", + "admin.nav.pricing": "Prezzi e Stripe", + "admin.nav.providers": "Fornitori", + "admin.nav.system": "Sistema", + "admin.nav.logs": "Log", + "admin.users.title": "Gestione Utenti", + "admin.users.subtitle": "Visualizza e gestisci gli account utente", + "admin.users.planUpdated": "Piano aggiornato", + "admin.users.planChanged": "Il piano è stato modificato in \\\"{plan}\\\" con successo.", + "admin.users.unknownError": "Errore sconosciuto", + "admin.users.error": "Errore", + "admin.users.planUpdateError": "Impossibile aggiornare il piano: {message}", + "admin.users.noKeys": "Nessuna chiave", + "admin.users.noKeysDesc": "Questo utente non ha chiavi API attive.", + "admin.users.keysRevoked": "Chiavi revocate", + "admin.users.keysRevokedDesc": "{count} chiave/i API revocata/e con successo.", + "admin.users.revokeError": "Impossibile revocare le chiavi: {message}", + "admin.users.retry": "Riprova", + "admin.system.title": "Sistema", + "admin.system.subtitle": "Monitora lo stato del sistema e gestisci le risorse", + "admin.system.quotas": "Quote di traduzione", + "admin.system.resetQuotas": "Ripristina quote mensili", + "admin.system.resetting": "Ripristino...", + "admin.system.reset": "Ripristina", + "admin.system.allOperational": "Tutti i sistemi operativi", + "admin.system.issuesDetected": "Problemi di sistema rilevati", + "admin.system.waitingData": "In attesa di dati...", + "admin.system.purging": "Pulizia in corso...", + "admin.system.clean": "Pulisci", + "admin.system.purge": "Pulisci" +} diff --git a/frontend/src/lib/i18n/messages/it/apiKeys.json b/frontend/src/lib/i18n/messages/it/apiKeys.json new file mode 100644 index 0000000..1c38722 --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/apiKeys.json @@ -0,0 +1,72 @@ +{ + "apiKeys.webhook.title": "Intégration Webhook", + "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", + "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", + "apiKeys.webhook.codeParam": "webhook_url", + "apiKeys.title": "Chiavi API", + "apiKeys.subtitle": "Gestisci le tue chiavi API per l'accesso programmatico all'API di traduzione.", + "apiKeys.loading": "Caricamento...", + "apiKeys.sectionTitle": "API e automazione", + "apiKeys.sectionDesc": "Genera e gestisci le tue chiavi API per i flussi di automazione", + "apiKeys.keysUsed": "{total} di {max} chiavi utilizzate", + "apiKeys.maxReached": "Numero massimo di chiavi raggiunto. Revoca una chiave per generarne una nuova.", + "apiKeys.canGenerate": "Puoi generare ancora {count} chiave", + "apiKeys.canGeneratePlural": "Puoi generare ancora {count} chiavi", + "apiKeys.generateNew": "Genera nuova chiave", + "apiKeys.keyRevoked": "Chiave revocata", + "apiKeys.keyRevokedDesc": "La chiave API è stata revocata con successo.", + "apiKeys.keyNotFound": "Chiave non trovata", + "apiKeys.keyNotFoundDesc": "La chiave API non esiste più. Potrebbe essere già stata revocata.", + "apiKeys.error": "Errore", + "apiKeys.revokeError": "Impossibile revocare la chiave API. Riprova.", + "apiKeys.limitReached": "Limite raggiunto", + "apiKeys.limitReachedDesc": "Hai raggiunto il massimo di 10 chiavi API. Revoca una chiave esistente per generarne una nuova.", + "apiKeys.proRequired": "Funzionalità Pro richiesta", + "apiKeys.proRequiredDesc": "Le chiavi API sono una funzionalità Pro. Aggiorna il tuo account.", + "apiKeys.generateError": "Impossibile generare la chiave API. Riprova.", + "apiKeys.upgrade.title": "Chiavi API", + "apiKeys.upgrade.subtitle": "Automatizza le tue traduzioni con l'accesso API", + "apiKeys.upgrade.feat1": "Genera chiavi API illimitate", + "apiKeys.upgrade.feat2": "Automatizza la traduzione dei documenti", + "apiKeys.upgrade.feat3": "Notifiche webhook", + "apiKeys.upgrade.feat4": "Modalità di traduzione LLM", + "apiKeys.upgrade.proFeature": "Le chiavi API sono una funzionalità {pro}. Aggiorna per sbloccare l'automazione API.", + "apiKeys.upgrade.pro": "Pro", + "apiKeys.upgrade.cta": "Passa a Pro", + "apiKeys.dialog.maxTitle": "Numero massimo di chiavi raggiunto", + "apiKeys.dialog.maxDesc": "Hai raggiunto il massimo di 10 chiavi API. Revoca una chiave esistente prima di generarne una nuova.", + "apiKeys.dialog.close": "Chiudi", + "apiKeys.dialog.generated": "Chiave API generata!", + "apiKeys.dialog.generatedDesc": "La tua nuova chiave API è stata creata. Copiala ora - non verrà più mostrata.", + "apiKeys.dialog.important": "Importante:", + "apiKeys.dialog.importantDesc": "Questa è l'unica volta che vedrai questa chiave. Conservala in modo sicuro.", + "apiKeys.dialog.apiKey": "Chiave API", + "apiKeys.dialog.name": "Nome:", + "apiKeys.dialog.done": "Fatto", + "apiKeys.dialog.copied": "Ho copiato la chiave", + "apiKeys.dialog.generateTitle": "Genera nuova chiave API", + "apiKeys.dialog.generateDesc": "Crea una nuova chiave API per l'accesso programmatico all'API di traduzione.", + "apiKeys.dialog.keyName": "Nome chiave (opzionale)", + "apiKeys.dialog.keyNamePlaceholder": "es. Produzione, Staging", + "apiKeys.dialog.keyNameHint": "Un nome descrittivo per identificare questa chiave in seguito.", + "apiKeys.dialog.nameTooLong": "Il nome deve contenere al massimo {max} caratteri", + "apiKeys.dialog.nameInvalid": "Il nome può contenere solo lettere, numeri, spazi, trattini e trattini bassi", + "apiKeys.dialog.cancel": "Annulla", + "apiKeys.dialog.generating": "Generazione...", + "apiKeys.dialog.generate": "Genera chiave", + "apiKeys.table.name": "Nome", + "apiKeys.table.prefix": "Prefisso", + "apiKeys.table.created": "Creata", + "apiKeys.table.lastUsed": "Ultimo utilizzo", + "apiKeys.table.never": "Mai", + "apiKeys.table.actions": "Azioni", + "apiKeys.table.revoke": "Revoca", + "apiKeys.table.copyPrefix": "Copia prefisso chiave", + "apiKeys.table.revokeKey": "Revoca chiave", + "apiKeys.revokeDialog.title": "Revoca chiave API", + "apiKeys.revokeDialog.desc": "Sei sicuro di voler revocare la chiave \\\"{name}\\\"? Questa azione non può essere annullata.", + "apiKeys.revokeDialog.confirm": "Sì, revoca", + "apiKeys.revokeDialog.cancel": "Annulla", + "apiKeys.noKeysGenerated": "Nessuna chiave generata", + "apiKeys.copied": "Copiato!" +} diff --git a/frontend/src/lib/i18n/messages/it/auth.json b/frontend/src/lib/i18n/messages/it/auth.json new file mode 100644 index 0000000..b300370 --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/auth.json @@ -0,0 +1,3 @@ +{ + "auth.brandName": "Wordly" +} diff --git a/frontend/src/lib/i18n/messages/it/checkout.json b/frontend/src/lib/i18n/messages/it/checkout.json new file mode 100644 index 0000000..3a49efe --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/checkout.json @@ -0,0 +1,12 @@ +{ + "checkout.activating": "Attivazione in corso…", + "checkout.activatingDesc": "Stiamo aggiornando il tuo abbonamento, attendi.", + "checkout.paymentConfirmed": "Pagamento confermato!", + "checkout.subscriptionActivated": "Abbonamento attivato!", + "checkout.planActivated": "Piano {plan} attivato!", + "checkout.redirectingToProfile": "Reindirizzamento al tuo profilo…", + "checkout.paymentReceived": "Pagamento ricevuto", + "checkout.redirecting": "Reindirizzamento…", + "checkout.syncError": "Errore di sincronizzazione", + "checkout.networkError": "Errore di rete. Il pagamento è confermato — ricarica il profilo." +} diff --git a/frontend/src/lib/i18n/messages/it/common.json b/frontend/src/lib/i18n/messages/it/common.json new file mode 100644 index 0000000..9ee9acf --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/common.json @@ -0,0 +1,4 @@ +{ + "common.loading": "Caricamento...", + "common.backToHome": "Torna alla home" +} diff --git a/frontend/src/lib/i18n/messages/it/context.json b/frontend/src/lib/i18n/messages/it/context.json new file mode 100644 index 0000000..99c614c --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/context.json @@ -0,0 +1,25 @@ +{ + "context.proTitle": "Funzionalità Pro", + "context.proDesc": "Il contesto e i glossari professionali sono disponibili con i piani Pro, Business ed Enterprise. Offrono traduzioni più accurate grazie a istruzioni e vocabolario specifici del tuo dominio.", + "context.viewPlans": "Vedi i piani", + "context.title": "Contesto e glossario", + "context.subtitle": "Migliora la qualità della traduzione con istruzioni e vocabolario specifici del tuo dominio.", + "context.presets.title": "Glossari professionali", + "context.presets.desc": "Carica un glossario completo con istruzioni e terminologia specializzata", + "context.instructions.title": "Istruzioni di contesto", + "context.instructions.desc": "Istruzioni che l'IA seguirà durante la traduzione", + "context.instructions.placeholder": "Es.: Traduci documenti tecnici HVAC. Utilizza terminologia ingegneristica precisa...", + "context.glossary.title": "Glossario tecnico", + "context.glossary.desc": "Formato: origine=destinazione (uno per riga). I glossari caricati tramite preset sono modificabili.", + "context.glossary.terms": "termini nel glossario", + "context.clearAll": "Cancella tutto", + "context.saving": "Salvataggio...", + "context.save": "Salva", + "context.presets.createGlossary": "Crea glossario", + "context.presets.created": "Glossario creato", + "context.presets.createdDesc": "Il glossario \\\"{name}\\\" è stato creato con {count} termini.", + "context.presets.hint": "Fai clic su un preset per creare un glossario con termini specifici del dominio. Gestisci i tuoi glossari nella sezione Glossari.", + "context.glossary.manage": "Gestisci glossari", + "context.saved": "Salvato", + "context.savedDesc": "Le tue istruzioni di contesto sono state salvate." +} diff --git a/frontend/src/lib/i18n/messages/it/cookieConsent.json b/frontend/src/lib/i18n/messages/it/cookieConsent.json new file mode 100644 index 0000000..474b1f5 --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/cookieConsent.json @@ -0,0 +1,7 @@ +{ + "cookieConsent.title": "Cookie su Wordly", + "cookieConsent.description": "Utilizziamo cookie essenziali per il funzionamento del servizio (sessione, sicurezza, lingua). Con il vostro consenso, utilizziamo anche cookie opzionali per misurare il traffico e migliorare il prodotto.", + "cookieConsent.acceptAll": "Accetta tutti", + "cookieConsent.essentialOnly": "Solo essenziali", + "cookieConsent.learnMore": "Scopri di più" +} diff --git a/frontend/src/lib/i18n/messages/it/dashboard.json b/frontend/src/lib/i18n/messages/it/dashboard.json new file mode 100644 index 0000000..c2df720 --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/dashboard.json @@ -0,0 +1,111 @@ +{ + "dashboard.nav.translate": "Traduci", + "dashboard.nav.profile": "Il mio profilo", + "dashboard.nav.settings": "Impostazioni", + "dashboard.nav.context": "Contesto", + "dashboard.nav.services": "Servizi", + "dashboard.nav.apiKeys": "Chiavi API", + "dashboard.nav.glossaries": "Glossari", + "dashboard.header.title": "Dashboard", + "dashboard.header.subtitle": "Gestisci le tue traduzioni", + "dashboard.header.toggleMenu": "Menu", + "dashboard.header.profileTitle": "Il mio profilo", + "dashboard.sidebar.theme": "Tema", + "dashboard.sidebar.signOut": "Esci", + "dashboard.sidebar.backHome": "Torna alla home", + "dashboard.sidebar.upgradeToPro": "Passa a Pro →", + "dashboard.translate.pageTitle": "Traduci un documento", + "dashboard.translate.pageSubtitle": "Importa un file e scegli la lingua di destinazione", + "dashboard.translate.errorNotificationTitle": "Errore", + "dashboard.translate.dropzone.uploadAria": "Area di rilascio file", + "dashboard.translate.dropzone.title": "Trascina qui il tuo file", + "dashboard.translate.dropzone.subtitle": "oppure clicca per selezionare (DOCX, XLSX, PPTX, PDF)", + "dashboard.translate.dropzone.replaceFile": "Sostituisci file", + "dashboard.translate.language.source": "Lingua di origine", + "dashboard.translate.language.target": "Lingua di destinazione", + "dashboard.translate.language.loading": "Caricamento lingue…", + "dashboard.translate.language.autoDetect": "Rilevamento automatico", + "dashboard.translate.language.selectPlaceholder": "Seleziona…", + "dashboard.translate.language.loadErrorPrefix": "Errore nel caricamento delle lingue", + "dashboard.translate.provider.loading": "Caricamento provider…", + "dashboard.translate.provider.noneConfigured": "Nessun provider configurato", + "dashboard.translate.provider.modelTitle": "Modello", + "dashboard.translate.provider.sectionTitle": "Provider", + "dashboard.translate.provider.llmDivider": "IA · Contestuale", + "dashboard.translate.provider.llmDividerPro": "IA · Contestuale (Pro)", + "dashboard.translate.provider.upgrade": "Passa a Pro", + "dashboard.translate.provider.upgradeSuffix": "per sbloccare la traduzione IA", + "dashboard.translate.trust.zeroRetention": "Zero conservazione", + "dashboard.translate.trust.deletedAfter": "File eliminati dopo l'elaborazione", + "dashboard.translate.actions.uploading": "Caricamento…", + "dashboard.translate.actions.translate": "Traduci", + "dashboard.translate.actions.filePrefix": "File: ", + "dashboard.translate.actions.cancel": "Annulla", + "dashboard.translate.actions.tryAgain": "Riprova", + "dashboard.translate.steps.uploading": "Caricamento file…", + "dashboard.translate.steps.starting": "Avvio traduzione…", + "dashboard.translate.complete.title": "Traduzione completata!", + "dashboard.translate.complete.descNamed": "Il tuo file {name} è stato tradotto correttamente.", + "dashboard.translate.complete.descGeneric": "Il tuo file è stato tradotto correttamente.", + "dashboard.translate.complete.downloading": "Download in corso…", + "dashboard.translate.complete.download": "Scarica", + "dashboard.translate.complete.newTranslation": "Nuova traduzione", + "dashboard.translate.complete.toastOkTitle": "Operazione riuscita", + "dashboard.translate.complete.toastOkDesc": "{name} è stato scaricato con successo.", + "dashboard.translate.complete.toastFailTitle": "Non riuscito", + "dashboard.translate.complete.toastFailDesc": "Traduzione non riuscita. Riprova.", + "dashboard.translate.sourceDocument": "Documento sorgente", + "dashboard.translate.configuration": "Configurazione", + "dashboard.translate.translating": "Traduzione in corso", + "dashboard.translate.liveMonitor": "Monitoraggio live", + "dashboard.translate.summary": "Riepilogo", + "dashboard.translate.engine": "Motore", + "dashboard.translate.confidence": "Confidenza", + "dashboard.translate.cancel": "Annulla", + "dashboard.translate.segments": "Segmenti", + "dashboard.translate.characters": "Caratteri", + "dashboard.translate.elapsed": "Trascorso", + "dashboard.translate.segPerMin": "Seg/min", + "dashboard.translate.highQuality": "Alta qualità", + "dashboard.translate.quality": "Qualità", + "dashboard.translate.completed": "Traduzione completata", + "dashboard.translate.replace": "Sostituisci", + "dashboard.translate.pdfMode.title": "Modalità traduzione PDF", + "dashboard.translate.pdfMode.preserveLayout": "Preserva layout", + "dashboard.translate.pdfMode.textOnly": "Solo testo", + "dashboard.translate.pdfMode.preserveLayoutDesc": "Mantiene immagini, tabelle e formattazione. Ideale per PDF semplici.", + "dashboard.translate.pdfMode.textOnlyDesc": "Traduce tutto il testo perfettamente. Output pulito, senza problemi di layout.", + "dashboard.translate.pipeline.upload": "Carica", + "dashboard.translate.pipeline.analyze": "Analizza", + "dashboard.translate.pipeline.translate": "Traduzione", + "dashboard.translate.pipeline.rebuild": "Ricostruisci", + "dashboard.translate.pipeline.finalize": "Finalizza", + "dashboard.translate.progress.processingFallback": "Elaborazione…", + "dashboard.translate.progress.connectionLost": "Connessione persa. Riprovo…", + "dashboard.translate.progress.failedTitle": "Traduzione fallita", + "dashboard.translate.error.unexpected": "Si è verificato un errore imprevisto. Riprova.", + "dashboard.translate.error.noResult": "La traduzione non ha prodotto risultati. Verifica che il documento contenga testo, quindi riprova o scegli un altro motore.", + "dashboard.translate.error.apiKey": "Chiave API non valida o mancante. Contatta l'amministratore per configurare le chiavi.", + "dashboard.translate.error.quota": "Limite di utilizzo raggiunto. Riprova tra qualche minuto o scegli un altro motore.", + "dashboard.translate.error.timeout": "Connessione al servizio di traduzione scaduta. Controlla la rete e riprova.", + "dashboard.translate.error.sessionExpired": "Sessione scaduta. Clicca su Riprova per riavviare la traduzione.", + "dashboard.translate.error.empty": "Il documento sembra vuoto o non contiene testo traducibile (PDF scansionato?).", + "dashboard.translate.error.unsupported": "Formato file non supportato o file danneggiato.", + "dashboard.translate.error.connection": "Connessione persa. Controlla la rete e riprova.", + "dashboard.translate.error.generic": "Traduzione fallita: {detail}", + "dashboard.translate.error.title": "Traduzione fallita", + "dashboard.translate.retry": "Riprova traduzione", + "dashboard.translate.newFile": "Nuovo file", + "dashboard.translate.modeAI": "Modalità IA", + "dashboard.translate.modeClassic": "Modalità Classica", + "dashboard.translate.glossaryLLMHint": "Glossari disponibili in modalità IA", + "dashboard.translate.submitting": "Invio in corso...", + "dashboard.translate.submit": "Avvia traduzione", + "dashboard.translate.noFile": "Carica prima un file", + "dashboard.translate.noTargetLang": "Seleziona una lingua di destinazione", + "dashboard.topbar.interfaceLabel": "Interfaccia di traduzione", + "dashboard.topbar.premiumAccess": "Accesso Premium", + "dashboard.checkoutSyncError": "Errore di sincronizzazione del pagamento.", + "dashboard.networkRefresh": "Errore di rete. Aggiorna la pagina.", + "dashboard.continueToTranslate": "Vai alla traduzione" +} diff --git a/frontend/src/lib/i18n/messages/it/fileUploader.json b/frontend/src/lib/i18n/messages/it/fileUploader.json new file mode 100644 index 0000000..245d8cc --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/fileUploader.json @@ -0,0 +1,31 @@ +{ + "fileUploader.uploadDocument": "Carica documento", + "fileUploader.uploadDesc": "Trascina o fai clic per selezionare un file (Excel, Word, PowerPoint)", + "fileUploader.dropHere": "Rilascia il file qui…", + "fileUploader.dragAndDrop": "Trascina il documento qui", + "fileUploader.orClickBrowse": "oppure fai clic per sfogliare", + "fileUploader.preview": "Anteprima", + "fileUploader.translationOptions": "Opzioni di traduzione", + "fileUploader.configureSettings": "Configura le impostazioni di traduzione", + "fileUploader.targetLanguage": "Lingua di destinazione", + "fileUploader.selectLanguage": "Seleziona lingua", + "fileUploader.translationProvider": "Provider di traduzione", + "fileUploader.selectProvider": "Seleziona provider", + "fileUploader.advancedOptions": "Opzioni avanzate", + "fileUploader.translateImages": "Traduci immagini", + "fileUploader.translating": "Traduzione in corso…", + "fileUploader.translateDocument": "Traduci documento", + "fileUploader.processing": "Elaborazione…", + "fileUploader.translationError": "Errore di traduzione", + "fileUploader.translationComplete": "Traduzione completata!", + "fileUploader.translationCompleteDesc": "Il documento è stato tradotto con successo mantenendo la formattazione.", + "fileUploader.download": "Scarica documento tradotto", + "fileUploader.webgpuUnsupported": "WebGPU non è supportato in questo browser. Usa Chrome 113+ o Edge 113+.", + "fileUploader.webllmNotLoaded": "Modello WebLLM non caricato. Vai a Impostazioni > Servizi di traduzione per caricare un modello.", + "fileUploader.extracting": "Estrazione dei testi dal documento…", + "fileUploader.noTranslatable": "Nessun testo traducibile trovato nel documento", + "fileUploader.foundTexts": "Trovati {count} testi da tradurre", + "fileUploader.translatingItem": "Traduzione {current}/{total}: «{preview}»", + "fileUploader.reconstructing": "Ricostruzione del documento…", + "fileUploader.translatingLocally": "Traduzione locale con WebLLM…" +} diff --git a/frontend/src/lib/i18n/messages/it/forgotPassword.json b/frontend/src/lib/i18n/messages/it/forgotPassword.json new file mode 100644 index 0000000..0ac67c8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/forgotPassword.json @@ -0,0 +1,14 @@ +{ + "forgotPassword.enterEmail": "Please enter your email address", + "forgotPassword.error": "An error occurred", + "forgotPassword.title": "Forgot Password", + "forgotPassword.checkEmail": "Check your inbox", + "forgotPassword.subtitle": "Enter your email to receive a reset link", + "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", + "forgotPassword.emailLabel": "Email address", + "forgotPassword.emailPlaceholder": "you@example.com", + "forgotPassword.sending": "Sending...", + "forgotPassword.sendLink": "Send reset link", + "forgotPassword.backToLogin": "Back to login", + "forgotPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/it/glossaries.json b/frontend/src/lib/i18n/messages/it/glossaries.json new file mode 100644 index 0000000..80ea9b9 --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/glossaries.json @@ -0,0 +1,189 @@ +{ + "glossaries.yourGlossaries": "I tuoi glossari", + "glossaries.title": "Glossari e Contesto", + "glossaries.description": "Gestisci i tuoi glossari e le istruzioni di contesto per traduzioni più precise.", + "glossaries.createNew": "Crea nuovo", + "glossaries.empty": "Nessun glossario", + "glossaries.emptyDesc": "Crea il tuo primo glossario o carica un preset professionale sopra", + "glossaries.defineTerms": "termini", + "glossaries.aboutTitle": "Informazioni sui glossari", + "glossaries.aboutDesc": "I glossari ti permettono di definire traduzioni esatte per termini specifici. Durante la traduzione, i termini del glossario garantiscono traduzioni coerenti e precise.", + "glossaries.aboutFormat": "Ogni termine ha una parola sorgente e traduzioni in più lingue. Seleziona un glossario nella pagina di traduzione per applicarlo.", + "glossaries.toast.created": "Glossario creato", + "glossaries.toast.createdDesc": "Il glossario \\\"{name}\\\" è stato creato.", + "glossaries.toast.imported": "Glossario importato", + "glossaries.toast.importedDesc": "Il glossario \\\"{name}\\\" è stato importato.", + "glossaries.toast.updated": "Glossario aggiornato", + "glossaries.toast.updatedDesc": "Il glossario \\\"{name}\\\" è stato aggiornato.", + "glossaries.toast.deleted": "Glossario eliminato", + "glossaries.toast.deletedDesc": "Il glossario è stato eliminato.", + "glossaries.toast.error": "Errore", + "glossaries.toast.errorCreate": "Impossibile creare il glossario", + "glossaries.toast.errorImport": "Impossibile importare il glossario", + "glossaries.toast.errorUpdate": "Impossibile aggiornare il glossario", + "glossaries.toast.errorDelete": "Impossibile eliminare il glossario", + "glossaries.dialog.title": "Nuovo glossario", + "glossaries.dialog.description": "Crea un glossario per le tue traduzioni", + "glossaries.dialog.nameLabel": "Nome", + "glossaries.dialog.namePlaceholder": "Il mio glossario", + "glossaries.dialog.tabTemplates": "Modelli", + "glossaries.dialog.tabFile": "File", + "glossaries.dialog.tabManual": "Manuale", + "glossaries.dialog.cancel": "Annulla", + "glossaries.dialog.creating": "Creazione…", + "glossaries.dialog.importing": "Importazione…", + "glossaries.dialog.importBtn": "Importa", + "glossaries.dialog.selectPrompt": "Seleziona", + "glossaries.dialog.createBtn": "Crea", + "glossaries.dialog.createEmpty": "Crea vuoto", + "glossaries.dialog.terms": "termini", + "glossaries.dialog.templatesDesc": "Scegli un modello predefinito", + "glossaries.dialog.templatesEmpty": "Nessun modello disponibile", + "glossaries.dialog.dropTitle": "Trascina qui un file CSV", + "glossaries.dialog.dropOr": "oppure", + "glossaries.dialog.dropFormats": "CSV, TSV, TXT", + "glossaries.termEditor.addTerm": "Aggiungi termine", + "glossaries.termEditor.maxReached": "Raggiunto il massimo di {max} termini per glossario.", + "glossaries.dialog.formatTitle": "Formato", + "glossaries.dialog.formatDesc": "origine,destinazione (uno per riga)", + "glossaries.dialog.formatNote": "La prima riga viene saltata se rilevata come intestazione", + "glossaries.dialog.errorFormat": "Formato non supportato", + "glossaries.dialog.errorSize": "File troppo grande", + "glossaries.dialog.errorEmpty": "File vuoto", + "glossaries.dialog.errorRead": "Errore di lettura", + "glossaries.dialog.parsing": "Analisi…", + "glossaries.dialog.termsImported": "termini importati", + "glossaries.dialog.changeFile": "Cambia file", + "glossaries.dialog.retry": "Riprova", + "glossaries.edit.title": "Modifier le glossaire", + "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", + "glossaries.edit.nameLabel": "Nom du glossaire", + "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", + "glossaries.edit.sourceLang": "Langue source", + "glossaries.edit.targetLang": "Langue cible", + "glossaries.edit.termsLabel": "Termes ({count} valides)", + "glossaries.edit.exportCsv": "Exporter CSV", + "glossaries.edit.importCsv": "Importer CSV", + "glossaries.edit.cancel": "Annuler", + "glossaries.edit.saving": "Enregistrement...", + "glossaries.edit.saveChanges": "Enregistrer les modifications", + "glossaries.edit.importFailedTitle": "Échec de l'importation", + "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", + "glossaries.edit.importSuccessTitle": "Importation réussie", + "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", + "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", + "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", + "glossaries.delete.title": "Supprimer le glossaire", + "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", + "glossaries.delete.warning": "Cette action est irréversible", + "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", + "glossaries.delete.cancel": "Annuler", + "glossaries.delete.deleting": "Suppression...", + "glossaries.delete.deleteBtn": "Supprimer", + "glossaries.upgrade.title": "Glossaires", + "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", + "glossaries.upgrade.feature1": "Créez plusieurs glossaires", + "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", + "glossaries.upgrade.feature3": "Importez/exportez via CSV", + "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", + "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", + "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", + "glossaries.upgrade.proLabel": "Pro", + "glossaries.upgrade.upgradeBtn": "Passer à Pro", + "glossaries.loading": "Chargement...", + "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", + "glossaries.howItWorks.step1Title": "Configurez ici", + "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", + "glossaries.howItWorks.step2Title": "Activez dans Traduire", + "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", + "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", + "glossaries.howItWorks.goToTranslate": "Aller à Traduire", + "glossaries.status.unsaved": "Non enregistré", + "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", + "glossaries.status.inactive": "Inactif", + "glossaries.instructions.whatForBold": "À quoi ça sert ?", + "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", + "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", + "glossaries.instructions.charCount": "{count} caractères", + "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", + "glossaries.instructions.clearAll": "Tout effacer", + "glossaries.instructions.saving": "Enregistrement…", + "glossaries.instructions.saved": "Enregistré", + "glossaries.presets.whatForBold": "À quoi ça sert ?", + "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", + "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", + "glossaries.presets.creating": "Création…", + "glossaries.presets.alreadyImported": "Déjà importé", + "glossaries.presets.it.title": "IT / Logiciel", + "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", + "glossaries.presets.legal.title": "Juridique / Contrats", + "glossaries.presets.legal.desc": "Droit des affaires, contentieux", + "glossaries.presets.medical.title": "Médical / Santé", + "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", + "glossaries.presets.finance.title": "Finance / Comptabilité", + "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", + "glossaries.presets.marketing.title": "Marketing / Publicité", + "glossaries.presets.marketing.desc": "Digital, branding, analytics", + "glossaries.presets.hr.title": "RH / Ressources Humaines", + "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", + "glossaries.presets.scientific.title": "Scientifique / Recherche", + "glossaries.presets.scientific.desc": "Publications, thèses, articles", + "glossaries.presets.ecommerce.title": "E-commerce / Vente", + "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", + "glossaries.grid.title": "Vos", + "glossaries.grid.titleHighlight": "glossaires", + "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", + "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", + "glossaries.grid.activeTranslation": "Traduction active :", + "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", + "glossaries.badge.compatible": "Compatible", + "glossaries.badge.otherTarget": "Autre cible", + "glossaries.card.editTerms": "Modifier les termes", + "glossaries.card.created": "Creato", + "glossaries.card.term": "termine", + "glossaries.card.delete": "Supprimer", + "glossaries.grid.searchPlaceholder": "Search a glossary…", + "glossaries.grid.noResults": "No results for this search.", + "glossaries.detail.backToList": "Back to glossaries", + "glossaries.detail.save": "Save", + "glossaries.detail.savedTitle": "Saved", + "glossaries.detail.savedDesc": "The glossary has been updated.", + "glossaries.detail.settingsTitle": "Settings", + "glossaries.detail.sourceLang": "Source language", + "glossaries.detail.targetLang": "Target language", + "glossaries.detail.termsTitle": "Terms", + "glossaries.detail.terms": "terms", + "glossaries.detail.searchTerms": "Filter…", + "glossaries.detail.noTerms": "No terms yet.", + "glossaries.detail.addFirstTerm": "Add the first term", + "glossaries.detail.addTerm": "Add a term", + "glossaries.detail.maxReached": "Maximum limit reached", + "glossaries.detail.source": "Source", + "glossaries.detail.target": "Target", + "glossaries.detail.sourcePlaceholder": "source term", + "glossaries.detail.targetPlaceholder": "target term", + "glossaries.detail.csvTitle": "CSV", + "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", + "glossaries.detail.export": "Export", + "glossaries.detail.import": "Import", + "glossaries.detail.dangerTitle": "Danger zone", + "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", + "glossaries.detail.deleteGlossary": "Delete this glossary", + "glossaries.detail.confirmDelete": "Confirm deletion?", + "glossaries.detail.confirm": "Confirm", + "glossaries.detail.cancel": "Cancel", + "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", + "glossaries.detail.sourceLocked": "fixed", + "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", + "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", + "glossaries.detail.notFoundTitle": "Glossary not found", + "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", + "glossaries.detail.maxTermsTitle": "Limit reached", + "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", + "glossaries.detail.importEmptyTitle": "Empty file", + "glossaries.detail.importEmptyDesc": "No terms detected in this file.", + "glossaries.detail.importedTitle": "Imported", + "glossaries.detail.importedDesc": "{count} terms imported.", + "glossaries.detail.importErrorTitle": "Read error", + "glossaries.detail.importErrorDesc": "Unable to read the file." +} diff --git a/frontend/src/lib/i18n/messages/it/index.ts b/frontend/src/lib/i18n/messages/it/index.ts new file mode 100644 index 0000000..5c35384 --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/index.ts @@ -0,0 +1,60 @@ +// Auto-generated by scripts/generate_i18n_index.py +// Merges all namespace JSON files for locale "it". + +import admin from "./admin.json"; +import apiKeys from "./apiKeys.json"; +import auth from "./auth.json"; +import checkout from "./checkout.json"; +import common from "./common.json"; +import context from "./context.json"; +import cookieConsent from "./cookieConsent.json"; +import dashboard from "./dashboard.json"; +import fileUploader from "./fileUploader.json"; +import forgotPassword from "./forgotPassword.json"; +import glossaries from "./glossaries.json"; +import landing from "./landing.json"; +import langSelector from "./langSelector.json"; +import layout from "./layout.json"; +import login from "./login.json"; +import memento from "./memento.json"; +import pricing from "./pricing.json"; +import profile from "./profile.json"; +import providerSelector from "./providerSelector.json"; +import providerTheme from "./providerTheme.json"; +import register from "./register.json"; +import resetPassword from "./resetPassword.json"; +import services from "./services.json"; +import settings from "./settings.json"; +import translate from "./translate.json"; +import translateComplete from "./translateComplete.json"; + +const messages: Record = { + ...admin, + ...apiKeys, + ...auth, + ...checkout, + ...common, + ...context, + ...cookieConsent, + ...dashboard, + ...fileUploader, + ...forgotPassword, + ...glossaries, + ...landing, + ...langSelector, + ...layout, + ...login, + ...memento, + ...pricing, + ...profile, + ...providerSelector, + ...providerTheme, + ...register, + ...resetPassword, + ...services, + ...settings, + ...translate, + ...translateComplete, +}; + +export default messages; diff --git a/frontend/src/lib/i18n/messages/it/landing.json b/frontend/src/lib/i18n/messages/it/landing.json new file mode 100644 index 0000000..d8f1d3f --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/landing.json @@ -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" +} diff --git a/frontend/src/lib/i18n/messages/it/langSelector.json b/frontend/src/lib/i18n/messages/it/langSelector.json new file mode 100644 index 0000000..0dd525a --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/langSelector.json @@ -0,0 +1,7 @@ +{ + "langSelector.search": "Cerca…", + "langSelector.noResults": "Nessun risultato", + "langSelector.source": "Origine", + "langSelector.target": "Destinazione", + "langSelector.swap": "Inverti" +} diff --git a/frontend/src/lib/i18n/messages/it/layout.json b/frontend/src/lib/i18n/messages/it/layout.json new file mode 100644 index 0000000..f53b178 --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/layout.json @@ -0,0 +1,5 @@ +{ + "layout.nav.apiAccess": "Accesso API", + "layout.footer.terms": "Termini", + "layout.footer.privacy": "Privacy" +} diff --git a/frontend/src/lib/i18n/messages/it/login.json b/frontend/src/lib/i18n/messages/it/login.json new file mode 100644 index 0000000..6d86dd4 --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/login.json @@ -0,0 +1,18 @@ +{ + "login.errorTitle": "Login Error", + "login.welcomeBack": "Welcome back", + "login.signInToContinue": "Sign in to continue translating", + "login.email": "Email", + "login.emailPlaceholder": "you@example.com", + "login.password": "Password", + "login.forgotPassword": "Forgot password?", + "login.passwordPlaceholder": "••••••••", + "login.signingIn": "Signing in...", + "login.signIn": "Sign In", + "login.noAccount": "Don't have an account?", + "login.signUpFree": "Sign up for free", + "login.orContinueWith": "oppure continua con e-mail", + "login.google.connecting": "Connessione…", + "login.google.errorGeneric": "Si è verificato un errore con l'accesso Google.", + "login.google.errorFailed": "Accesso con Google non riuscito. Riprova." +} diff --git a/frontend/src/lib/i18n/messages/it/memento.json b/frontend/src/lib/i18n/messages/it/memento.json new file mode 100644 index 0000000..087b9ce --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/memento.json @@ -0,0 +1,6 @@ +{ + "memento.title": "Scopri Momento", + "memento.slogan": "Momento non è solo un'app di note. È un ecosistema intelligente che connette, analizza e sviluppa le tue idee in tempo reale usando 6 agenti IA e ricerca semantica avanzata.", + "memento.ctaFree": "Inizia gratis", + "memento.ctaMore": "Scopri di più" +} diff --git a/frontend/src/lib/i18n/messages/it/pricing.json b/frontend/src/lib/i18n/messages/it/pricing.json new file mode 100644 index 0000000..21d8cf8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/pricing.json @@ -0,0 +1,151 @@ +{ + "pricing.nav.back": "Indietro", + "pricing.nav.home": "Home", + "pricing.nav.mySubscription": "Il mio abbonamento", + "pricing.header.badge": "Modelli IA aggiornati — Marzo 2026", + "pricing.header.title": "Un piano per ogni esigenza", + "pricing.header.subtitle": "Traduci i tuoi documenti Word, Excel e PowerPoint mantenendo la formattazione originale. Nessuna chiave API richiesta.", + "pricing.billing.monthly": "Mensile", + "pricing.billing.yearly": "Annuale", + "pricing.plans.free.name": "Gratuito", + "pricing.plans.starter.name": "Starter", + "pricing.plans.pro.name": "Pro", + "pricing.plans.business.name": "Business", + "pricing.plans.enterprise.name": "Enterprise", + "pricing.plans.free.description": "Perfetto per scoprire l'app", + "pricing.plans.starter.description": "Per privati e piccoli progetti", + "pricing.plans.pro.description": "Per professionisti e team in crescita", + "pricing.plans.business.description": "Per team e organizzazioni", + "pricing.plans.enterprise.description": "Soluzioni personalizzate per grandi organizzazioni", + "pricing.plans.pro.highlight": "Il più popolare", + "pricing.plans.pro.badge": "POPOLARE", + "pricing.plans.enterprise.badge": "SU RICHIESTA", + "pricing.plans.free.feat1": "5 documenti / mese", + "pricing.plans.free.feat2": "Fino a 15 pagine per documento", + "pricing.plans.free.feat3": "Google Traduttore incluso", + "pricing.plans.free.feat4": "Tutte le lingue (130+)", + "pricing.plans.free.feat5": "Supporto della community", + "pricing.plans.starter.feat1": "50 documenti / mese", + "pricing.plans.starter.feat2": "Fino a 50 pagine per documento", + "pricing.plans.starter.feat3": "Google Traduttore + DeepL", + "pricing.plans.starter.feat4": "File fino a 10 MB", + "pricing.plans.starter.feat5": "Supporto via e-mail", + "pricing.plans.starter.feat6": "Cronologia di 30 giorni", + "pricing.plans.pro.feat1": "200 documenti / mese", + "pricing.plans.pro.feat2": "Fino a 200 pagine per documento", + "pricing.plans.pro.feat3": "Traduzione IA Essenziale", + "pricing.plans.pro.feat4": "Google Traduttore + DeepL", + "pricing.plans.pro.feat5": "File fino a 25 MB", + "pricing.plans.pro.feat6": "Glossari personalizzati", + "pricing.plans.pro.feat7": "Supporto prioritario", + "pricing.plans.pro.feat8": "Cronologia di 90 giorni", + "pricing.plans.business.feat1": "1 000 documenti / mese", + "pricing.plans.business.feat2": "Fino a 500 pagine per documento", + "pricing.plans.business.feat3": "IA Essenziale + Premium (Claude Haiku)", + "pricing.plans.business.feat4": "Tutti i provider di traduzione", + "pricing.plans.business.feat5": "File fino a 50 MB", + "pricing.plans.business.feat6": "Accesso API (10 000 chiamate/mese)", + "pricing.plans.business.feat7": "Webhook di notifica", + "pricing.plans.business.feat8": "Supporto dedicato", + "pricing.plans.business.feat9": "Cronologia di 1 anno", + "pricing.plans.business.feat10": "Analisi avanzate", + "pricing.plans.enterprise.feat1": "Documenti illimitati", + "pricing.plans.enterprise.feat2": "Tutti i modelli IA (GPT-5, Claude Opus 4.6…)", + "pricing.plans.enterprise.feat3": "Distribuzione on-premise o cloud dedicato", + "pricing.plans.enterprise.feat4": "SLA 99,9 % garantito", + "pricing.plans.enterprise.feat5": "Supporto dedicato 24/7", + "pricing.plans.enterprise.feat6": "White-label", + "pricing.plans.enterprise.feat7": "Team illimitati", + "pricing.plans.enterprise.feat8": "Integrazioni personalizzate", + "pricing.card.onRequest": "Su richiesta", + "pricing.card.free": "Gratuito", + "pricing.card.perMonth": "/mese", + "pricing.card.billedYearly": "Fatturato {price} € / anno", + "pricing.card.documents": "Documenti", + "pricing.card.pagesMax": "Pagine max", + "pricing.card.aiTranslation": "Traduzione IA", + "pricing.card.unlimited": "Illimitato", + "pricing.card.perMonthStat": "/ mese", + "pricing.card.perDoc": "p / doc", + "pricing.card.aiEssential": "Essenziale", + "pricing.card.aiEssentialPremium": "Essenziale + Premium", + "pricing.card.aiCustom": "Personalizzato", + "pricing.card.myPlan": "Il mio piano", + "pricing.card.managePlan": "Gestisci il mio piano", + "pricing.card.startFree": "Inizia gratuitamente", + "pricing.card.contactUs": "Contattaci", + "pricing.card.choosePlan": "Scegli questo piano", + "pricing.card.processing": "Elaborazione…", + "pricing.comparison.title": "Confronto dettagliato", + "pricing.comparison.subtitle": "Tutto ciò che include ogni piano", + "pricing.comparison.feature": "Funzionalità", + "pricing.comparison.docsPerMonth": "Documenti / mese", + "pricing.comparison.pagesMaxPerDoc": "Pagine max / documento", + "pricing.comparison.maxFileSize": "Dimensione max file", + "pricing.comparison.googleTranslation": "Google Traduttore", + "pricing.comparison.deepl": "DeepL", + "pricing.comparison.aiEssential": "Traduzione IA Essenziale", + "pricing.comparison.aiPremium": "Traduzione IA Premium", + "pricing.comparison.apiAccess": "Accesso API", + "pricing.comparison.priorityProcessing": "Elaborazione prioritaria", + "pricing.comparison.support": "Supporto", + "pricing.comparison.support.community": "Community", + "pricing.comparison.support.email": "E-mail", + "pricing.comparison.support.priority": "Prioritario", + "pricing.comparison.support.dedicated": "Dedicato", + "pricing.comparison.mb": "MB", + "pricing.credits.title": "Crediti aggiuntivi", + "pricing.credits.subtitle": "Ne serve di più? Acquista crediti singoli, senza abbonamento.", + "pricing.credits.perPage": "1 credito = 1 pagina tradotta.", + "pricing.credits.bestValue": "Miglior rapporto qualità-prezzo", + "pricing.credits.unit": "crediti", + "pricing.credits.centsPerCredit": "cts / credito", + "pricing.credits.buy": "Acquista", + "pricing.trust.encryption.title": "Crittografia end-to-end", + "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 a riposo", + "pricing.trust.languages.title": "130+ lingue", + "pricing.trust.languages.sub": "Tra cui arabo, persiano, ebraico (RTL)", + "pricing.trust.parallel.title": "Elaborazione parallela", + "pricing.trust.parallel.sub": "IA multi-thread ultraveloce", + "pricing.trust.availability.title": "Disponibile 24/7", + "pricing.trust.availability.sub": "99,9 % di uptime garantito", + "pricing.aiModels.title": "I nostri modelli IA — Marzo 2026", + "pricing.aiModels.essential.title": "Traduzione IA Essenziale", + "pricing.aiModels.essential.plan": "Piano Pro", + "pricing.aiModels.essential.descPrefix": "Basato su", + "pricing.aiModels.essential.descSuffix": "— il modello IA più conveniente del 2026. Qualità paragonabile ai modelli frontier a una frazione del costo.", + "pricing.aiModels.essential.modelName": "il nostro modello IA Essenziale", + "pricing.aiModels.essential.context": "163K token di contesto", + "pricing.aiModels.essential.value": "Eccellente rapporto qualità-prezzo", + "pricing.aiModels.premium.title": "Traduzione IA Premium", + "pricing.aiModels.premium.plan": "Piano Business", + "pricing.aiModels.premium.descPrefix": "Basato su", + "pricing.aiModels.premium.descSuffix": "di Anthropic — preciso su documenti legali, medici e tecnici complessi.", + "pricing.aiModels.premium.context": "200K token di contesto", + "pricing.aiModels.premium.precision": "Massima precisione", + "pricing.faq.title": "Domande frequenti", + "pricing.faq.q1": "Posso cambiare piano in qualsiasi momento?", + "pricing.faq.a1": "Sì. Il passaggio a un piano superiore è immediato e proporzionale. Il downgrade sarà attivo alla fine del periodo corrente.", + "pricing.faq.q2": "Cos'è la «Traduzione IA Essenziale»?", + "pricing.faq.a2": "È il nostro motore IA. Comprende il contesto dei vostri documenti, preserva il layout e gestisce i termini tecnici molto meglio della traduzione classica.", + "pricing.faq.q3": "Qual è la differenza tra IA Essenziale e IA Premium?", + "pricing.faq.a3": "La IA Essenziale usa un modello ottimizzato (eccellente rapporto qualità/prezzo). La IA Premium usa Claude 3.5 Haiku di Anthropic, più precisa su documenti legali, medici e tecnici complessi.", + "pricing.faq.q4": "I miei documenti vengono conservati dopo la traduzione?", + "pricing.faq.a4": "I file tradotti sono disponibili secondo il tuo piano (30 giorni Starter, 90 giorni Pro, 1 anno Business). Sono crittografati a riposo e in transito.", + "pricing.faq.q5": "Cosa succede se supero la quota mensile?", + "pricing.faq.a5": "Puoi acquistare crediti aggiuntivi singolarmente o fare upgrade del piano. Riceverai una notifica al raggiungimento dell'80 % di utilizzo.", + "pricing.faq.q6": "C'è un periodo di prova gratuito per i piani a pagamento?", + "pricing.faq.a6": "Il piano Gratuito è permanente e non richiede carta di credito. Per i piani Pro e Business, contattaci per una prova di 14 giorni.", + "pricing.faq.q7": "Quali formati di file sono supportati?", + "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx) e presto PDF. Tutti i piani supportano gli stessi formati.", + "pricing.cta.title": "Pronto per iniziare?", + "pricing.cta.subtitle": "Inizia gratuitamente, senza carta di credito. Fai upgrade quando ne hai bisogno.", + "pricing.cta.createAccount": "Crea un account gratuito", + "pricing.cta.login": "Accedi", + "pricing.toast.demo": "Modalità demo — Stripe non è ancora configurato. In produzione, saresti reindirizzato al pagamento per attivare il piano {planId}.", + "pricing.toast.networkError": "Errore di rete. Riprova.", + "pricing.toast.paymentError": "Errore durante la creazione del pagamento.", + "pricing.dashboard": "Dashboard", + "pricing.okSymbol": "✓", + "pricing.errSymbol": "✕" +} diff --git a/frontend/src/lib/i18n/messages/it/profile.json b/frontend/src/lib/i18n/messages/it/profile.json new file mode 100644 index 0000000..3061bd9 --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/profile.json @@ -0,0 +1,58 @@ +{ + "profile.header.title": "Il mio profilo", + "profile.header.subtitle": "Gestisci il tuo account e le tue preferenze.", + "profile.tabs.account": "Account", + "profile.tabs.subscription": "Abbonamento", + "profile.tabs.preferences": "Preferenze", + "profile.account.user": "Utente", + "profile.account.memberSince": "Membro dal", + "profile.plan.label": "Piano", + "profile.plan.free": "Free", + "profile.plan.starter": "Starter", + "profile.plan.pro": "Pro", + "profile.plan.business": "Business", + "profile.plan.enterprise": "Enterprise", + "profile.plan.pricePerMonth": "{price} €/mese", + "profile.subscription.canceling": "In cancellazione", + "profile.subscription.active": "Attivo", + "profile.subscription.unknown": "Sconosciuto", + "profile.subscription.accessUntil": "Accesso fino al", + "profile.subscription.renewalOn": "Rinnovo il", + "profile.subscription.upgradePlan": "Passa a un piano a pagamento", + "profile.subscription.changePlan": "Cambia piano", + "profile.subscription.manageBilling": "Gestisci fatturazione", + "profile.subscription.billingUnavailable": "Portale di fatturazione non disponibile.", + "profile.subscription.billingError": "Errore di accesso al portale di fatturazione.", + "profile.subscription.cancelSuccess": "Abbonamento cancellato. Mantieni l'accesso fino alla fine del periodo.", + "profile.subscription.cancelError": "Errore durante la cancellazione.", + "profile.subscription.networkError": "Errore di rete.", + "profile.usage.title": "Utilizzo di questo mese", + "profile.usage.resetOn": "Azzeramento il", + "profile.usage.documents": "Documenti", + "profile.usage.pages": "Pagine", + "profile.usage.extraCredits": "credito extra", + "profile.usage.extraCreditsPlural": "crediti extra", + "profile.usage.quotaReached": "Quota raggiunta", + "profile.usage.quotaReachedDesc": "Passa a un piano superiore per continuare.", + "profile.usage.unlockMore": "Sblocca più traduzioni con un piano a pagamento.", + "profile.usage.viewPlans": "Vedi i piani", + "profile.usage.includedInPlan": "Incluso nel tuo piano", + "profile.danger.title": "Zona pericolosa", + "profile.danger.description": "La cancellazione avrà effetto alla fine del periodo corrente. Mantieni l'accesso fino a quella data.", + "profile.danger.confirm": "Sei sicuro? Questa azione non può essere annullata.", + "profile.danger.confirmCancel": "Conferma cancellazione", + "profile.danger.cancelSubscription": "Cancella il mio abbonamento", + "profile.danger.keep": "No, mantieni", + "profile.prefs.interfaceLang": "Lingua dell'interfaccia", + "profile.prefs.interfaceLangDesc": "La lingua viene rilevata automaticamente in base al tuo browser. Puoi cambiarla manualmente.", + "profile.prefs.defaultTargetLang": "Lingua di destinazione predefinita", + "profile.prefs.selectLanguage": "Seleziona una lingua", + "profile.prefs.defaultTargetLangDesc": "Questa lingua sarà preselezionata per le tue traduzioni.", + "profile.prefs.save": "Salva", + "profile.prefs.theme": "Tema", + "profile.prefs.themeDesc": "Scegli l'aspetto dell'interfaccia", + "profile.prefs.cache": "Cache", + "profile.prefs.cacheDesc": "Svuotare la cache locale può risolvere alcuni problemi di visualizzazione.", + "profile.prefs.clearing": "Svuotamento...", + "profile.prefs.clearCache": "Svuota cache" +} diff --git a/frontend/src/lib/i18n/messages/it/providerSelector.json b/frontend/src/lib/i18n/messages/it/providerSelector.json new file mode 100644 index 0000000..4ca922b --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/providerSelector.json @@ -0,0 +1,7 @@ +{ + "providerSelector.noClassic": "Nessun traduttore standard disponibile.", + "providerSelector.noLlm": "Nessun modello IA configurato.", + "providerSelector.costOne": "Costo: 1 credito per pagina", + "providerSelector.costFive": "Costo: 5 crediti per pagina (Fattore Premium)", + "providerSelector.unlockContextual": "Sblocca la traduzione contestuale premium per i tuoi documenti interi." +} diff --git a/frontend/src/lib/i18n/messages/it/providerTheme.json b/frontend/src/lib/i18n/messages/it/providerTheme.json new file mode 100644 index 0000000..de6b114 --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/providerTheme.json @@ -0,0 +1,29 @@ +{ + "providerTheme.deepseek.badge": "Essenziale", + "providerTheme.deepseek.subBadge": "Tecnico ed economico", + "providerTheme.deepseek.desc": "Traduzione ultra-precisa ed economica, ideale per documenti tecnici e codice.", + "providerTheme.openai.badge": "Premium", + "providerTheme.openai.subBadge": "Alta fedeltà", + "providerTheme.openai.desc": "Lo standard globale dell'IA. Massima coerenza testuale e rispetto rigoroso dello stile.", + "providerTheme.minimax.badge": "Avanzata", + "providerTheme.minimax.subBadge": "Prestazioni", + "providerTheme.minimax.desc": "Velocità di esecuzione incredibile e comprensione eccellente di strutture complesse.", + "providerTheme.openrouter.badge": "Express", + "providerTheme.openrouter.subBadge": "Multi-modello", + "providerTheme.openrouter.desc": "Accesso unificato ai migliori modelli open-source ottimizzati per la traduzione.", + "providerTheme.openrouter_premium.badge": "Ultra", + "providerTheme.openrouter_premium.subBadge": "Contesto massimo", + "providerTheme.openrouter_premium.desc": "Assistito da modelli all'avanguardia (GPT-4o, Claude Sonnet 4.6) per documenti lunghi.", + "providerTheme.zai.badge": "Specializzata", + "providerTheme.zai.subBadge": "Finanza e Diritto", + "providerTheme.zai.desc": "Modello ottimizzato per terminologie aziendali impegnative (legale, finanza).", + "providerTheme.default.badge": "Moderno", + "providerTheme.default.subBadge": "Ragionamento IA", + "providerTheme.default.desc": "Traduzione con modello linguistico di grandi dimensioni (LLM) con analisi semantica avanzata.", + "providerTheme.classic.google.label": "Google Traduttore", + "providerTheme.classic.google.desc": "Traduzione ultra-veloce che copre oltre 130 lingue. Consigliata per flussi generali.", + "providerTheme.classic.deepl.label": "DeepL Pro", + "providerTheme.classic.deepl.desc": "Traduzione ad alta precisione rinomata per la sua fluidità e formulazioni naturali.", + "providerTheme.classic.google_cloud.label": "Google Cloud API", + "providerTheme.classic.google_cloud.desc": "Motore cloud professionale ottimizzato per l'elaborazione di grandi volumi di documenti." +} diff --git a/frontend/src/lib/i18n/messages/it/register.json b/frontend/src/lib/i18n/messages/it/register.json new file mode 100644 index 0000000..1fc968d --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/register.json @@ -0,0 +1,29 @@ +{ + "register.title": "Crea un account", + "register.subtitle": "Inizia a tradurre gratuitamente", + "register.error.failed": "Registrazione non riuscita", + "register.name.label": "Nome", + "register.name.placeholder": "Il tuo nome", + "register.name.error": "Il nome deve contenere almeno 2 caratteri", + "register.email.label": "Indirizzo e-mail", + "register.email.placeholder": "tu@esempio.com", + "register.email.error": "Indirizzo e-mail non valido", + "register.password.label": "Password", + "register.password.error": "La password deve contenere almeno 8 caratteri, una maiuscola, una minuscola e una cifra", + "register.password.show": "Mostra password", + "register.password.hide": "Nascondi password", + "register.password.strengthLabel": "Sicurezza:", + "register.password.strength.weak": "Debole", + "register.password.strength.medium": "Media", + "register.password.strength.strong": "Forte", + "register.confirmPassword.label": "Conferma password", + "register.confirmPassword.error": "Le password non coincidono", + "register.confirmPassword.show": "Mostra", + "register.confirmPassword.hide": "Nascondi", + "register.submit.creating": "Creazione account...", + "register.submit.create": "Crea il mio account", + "register.hasAccount": "Hai già un account?", + "register.login": "Accedi", + "register.terms.prefix": "Creando un account, accetti i nostri", + "register.terms.link": "termini di servizio" +} diff --git a/frontend/src/lib/i18n/messages/it/resetPassword.json b/frontend/src/lib/i18n/messages/it/resetPassword.json new file mode 100644 index 0000000..680714f --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/resetPassword.json @@ -0,0 +1,22 @@ +{ + "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", + "resetPassword.passwordMismatch": "Passwords do not match", + "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", + "resetPassword.error": "An error occurred", + "resetPassword.invalidLink": "Invalid link", + "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", + "resetPassword.requestNewLink": "Request new link", + "resetPassword.successTitle": "Password reset", + "resetPassword.newPasswordTitle": "New password", + "resetPassword.successSubtitle": "You will be redirected to login", + "resetPassword.subtitle": "Set your new password", + "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", + "resetPassword.newPassword": "New password", + "resetPassword.showPassword": "Show password", + "resetPassword.hidePassword": "Hide password", + "resetPassword.confirmPassword": "Confirm password", + "resetPassword.resetting": "Resetting...", + "resetPassword.resetPassword": "Reset password", + "resetPassword.backToLogin": "Back to login", + "resetPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/it/services.json b/frontend/src/lib/i18n/messages/it/services.json new file mode 100644 index 0000000..2d6855b --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/services.json @@ -0,0 +1,14 @@ +{ + "services.title": "Fornitori di traduzione", + "services.subtitle": "I fornitori sono configurati dall'amministratore. Puoi vedere quali sono attualmente disponibili per il tuo account.", + "services.loading": "Caricamento fornitori...", + "services.noProviders": "Nessun fornitore attualmente configurato. Contatta il tuo amministratore.", + "services.classic": "Traduzione classica", + "services.llmPro": "LLM · Contestuale (Pro)", + "services.available": "Disponibile", + "services.model": "Modello", + "services.adminOnly.title": "La configurazione dei fornitori è riservata all'amministratore", + "services.adminOnly.desc": "Le chiavi API, la selezione dei modelli e l'attivazione dei fornitori sono gestite esclusivamente dall'amministratore nel pannello admin. Non è necessario inserire alcuna chiave API.", + "services.fallback.google.label": "Google Traduttore", + "services.fallback.google.desc": "Traduzione rapida, oltre 130 lingue" +} diff --git a/frontend/src/lib/i18n/messages/it/settings.json b/frontend/src/lib/i18n/messages/it/settings.json new file mode 100644 index 0000000..344ec74 --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/settings.json @@ -0,0 +1,20 @@ +{ + "settings.title": "Impostazioni", + "settings.subtitle": "Configurazione generale dell'applicazione", + "settings.formats.title": "Formati supportati", + "settings.formats.subtitle": "Tipi di documento che puoi tradurre", + "settings.formats.formulas": "Formule", + "settings.formats.styles": "Stili", + "settings.formats.images": "Immagini", + "settings.formats.headers": "Intestazioni", + "settings.formats.tables": "Tabelle", + "settings.formats.slides": "Diapositive", + "settings.formats.notes": "Note", + "settings.cache.title": "Cache", + "settings.cache.desc": "Svuotare la cache locale può risolvere alcuni problemi di visualizzazione.", + "settings.cache.clearing": "Svuotamento...", + "settings.cache.clear": "Svuota cache", + "settings.formats.excel.name": "Excel", + "settings.formats.word.name": "Word", + "settings.formats.powerpoint.name": "PowerPoint" +} diff --git a/frontend/src/lib/i18n/messages/it/translate.json b/frontend/src/lib/i18n/messages/it/translate.json new file mode 100644 index 0000000..207e3de --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/translate.json @@ -0,0 +1,92 @@ +{ + "translate.mode.label": "Mode de traduction", + "translate.mode.classic": "Classique", + "translate.mode.classicDesc": "Rapide", + "translate.mode.proLlm": "Pro LLM", + "translate.mode.proLlmDesc": "Contextuel", + "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", + "translate.mode.upgradeLink": "Passer à Pro", + "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", + "translate.glossary.title": "Glossario", + "translate.glossary.select": "Seleziona glossario", + "translate.glossary.none": "Nessuno", + "translate.glossary.terms": "termini", + "translate.glossary.proOnly": "Passa a Pro per usare i glossari", + "translate.glossary.myGlossaries": "I miei glossari", + "translate.glossary.fromTemplate": "Crea da modello", + "translate.glossary.noGlossaryForPair": "Nessun glossario per", + "translate.glossary.noGlossaries": "Nessun glossario", + "translate.glossary.loading": "Caricamento...", + "translate.glossary.classicMode": "Motore neutro senza glossario (solo IA)", + "translate.glossary.selectPlaceholder": "Selezionare un glossario...", + "translate.glossary.multilingual": "MULTILINGUE", + "translate.glossary.noGlossaryAvailable": "Nessun glossario disponibile", + "translate.glossary.filterByLang": "Filtra per lingua", + "translate.glossary.active": "Attivo", + "translate.glossary.inactive": "Inattivo", + "translate.glossary.availableTemplates": "Modelli disponibili", + "translate.glossary.importing": "Importazione...", + "translate.glossary.imported": "(Importato)", + "translate.glossary.noGlossaryForSource": "Nessun glossario o modello per la lingua di origine", + "translate.glossary.createGlossary": "Crea un glossario", + "translate.glossary.showAll": "Mostra tutti i glossari", + "translate.glossary.activePreview": "Anteprima delle corrispondenze attive:", + "translate.glossary.total": "in totale", + "translate.glossary.moreTerms": "altri termini", + "translate.glossary.noTerms": "Nessun termine in questo glossario.", + "translate.glossary.sourceTerm": "Termine sorgente", + "translate.glossary.translation": "Traduzione", + "translate.glossary.addTerm": "Aggiungi termine", + "translate.glossary.disabledMode": "Motore neutro senza glossario applicato", + "translate.glossary.addTermError": "Errore durante l'aggiunta del termine", + "translate.glossary.networkError": "Errore di rete", + "translate.glossary.importFailed": "Importazione fallita ({status})", + "translate.glossary.helpText": "Il glossario forza la traduzione precisa dei termini. Scegli un glossario la cui lingua sorgente corrisponde alla lingua originale del documento.", + "translate.glossary.sourceWarning": "Attenzione: Questo glossario utilizza la lingua sorgente", + "translate.glossary.sourceWarningBut": "ma il documento è configurato in", + "translate.glossary.targetWarning": "Incompatibilità di destinazione: Questo glossario è progettato per tradurre verso", + "translate.glossary.targetWarningBut": "ma il documento ha come destinazione", + "translate.glossary.targetWarningEnd": "I termini potrebbero non essere pertinenti.", + "translate.header.processing": "Elaborazione in corso", + "translate.header.aiActive": "Analisi IA attiva", + "translate.header.aiActiveDesc": "Il tuo layout viene preservato dal nostro motore contestuale.", + "translate.header.completed": "Completato", + "translate.header.completedTitle": "Traduzione completata", + "translate.header.proSpace": "Spazio Pro", + "translate.header.translateDoc": "Traduci un documento", + "translate.header.translateDocDesc": "Preserva il layout originale con il nostro motore di traduzione ultra-alta-fedeltà.", + "translate.upload.nativeFormat": "Formato nativo", + "translate.fileType.word": "Word (.docx)", + "translate.fileType.excel": "Excel (.xlsx)", + "translate.fileType.slides": "Diapositive (.pptx)", + "translate.fileType.pdf": "PDF (.pdf)", + "translate.startTranslation": "Avvia traduzione", + "translate.submit": "Invio…", + "translate.chooseTargetLang": "Seleziona una lingua di destinazione", + "translate.pleaseLoadFile": "Carica prima un file", + "translate.contextEngineActive": "Motore contestuale attivo", + "translate.phase1": "Fase 1: Inizializzazione", + "translate.phase2": "Fase 2: Ricostruzione contestuale", + "translate.stat.segments": "segmenti", + "translate.stat.precision": "precisione", + "translate.stat.speedLabel": "velocità", + "translate.stat.turbo": "Turbo", + "translate.stat.time": "tempo", + "translate.complete.masterQuality": "✓ Qualità master", + "translate.download": "Scarica", + "translate.newTranslation": "+ Nuova traduzione", + "translate.failedTitle": "Errore di traduzione", + "translate.retry": "Riprova", + "translate.uploadAnother": "Carica un altro file", + "translate.monitor": "Monitor IA", + "translate.summary": "Riepilogo", + "translate.cancelProcess": "⟳ Annulla il processo", + "translate.layoutIntegrity": "Integrità del layout", + "translate.secureHundred": "100% SICURO", + "translate.okHundred": "100% OK", + "translate.preserveLayout": "Mantieni layout", + "translate.preserveLayoutDesc": "Mantieni il layout", + "translate.textOnly": "Solo testo", + "translate.textOnlyDesc": "Traduzione rapida solo del testo", + "translate.unavailableStandard": "Non disponibile in modalità Standard (solo IA)" +} diff --git a/frontend/src/lib/i18n/messages/it/translateComplete.json b/frontend/src/lib/i18n/messages/it/translateComplete.json new file mode 100644 index 0000000..9c88ad0 --- /dev/null +++ b/frontend/src/lib/i18n/messages/it/translateComplete.json @@ -0,0 +1,6 @@ +{ + "translateComplete.highQuality": "Alta qualità", + "translateComplete.segments": "Segmenti", + "translateComplete.characters": "Caratteri", + "translateComplete.confidence": "Affidabilità" +} diff --git a/frontend/src/lib/i18n/messages/ja/admin.json b/frontend/src/lib/i18n/messages/ja/admin.json new file mode 100644 index 0000000..b177be8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/admin.json @@ -0,0 +1,48 @@ +{ + "admin.login.title": "管理画面", + "admin.login.required": "ログインが必要です", + "admin.login.password": "管理者パスワード", + "admin.login.connecting": "接続中...", + "admin.login.access": "管理画面にアクセス", + "admin.login.restricted": "管理者のみアクセス可能", + "admin.layout.checking": "認証を確認中...", + "admin.dashboard.title": "管理ダッシュボード", + "admin.dashboard.subtitle": "管理者コントロールパネル", + "admin.dashboard.refresh": "更新", + "admin.dashboard.refreshTooltip": "ダッシュボードデータを更新", + "admin.dashboard.config": "システム設定", + "admin.dashboard.maxFileSize": "最大ファイルサイズ:", + "admin.dashboard.translationService": "翻訳サービス:", + "admin.dashboard.formats": "対応形式:", + "admin.nav.dashboard": "Dashboard", + "admin.nav.users": "ユーザー", + "admin.nav.pricing": "料金と Stripe", + "admin.nav.providers": "プロバイダー", + "admin.nav.system": "システム", + "admin.nav.logs": "ログ", + "admin.users.title": "ユーザー管理", + "admin.users.subtitle": "ユーザーアカウントの表示と管理", + "admin.users.planUpdated": "プランが更新されました", + "admin.users.planChanged": "プランが「{plan}」に正常に変更されました。", + "admin.users.unknownError": "不明なエラー", + "admin.users.error": "エラー", + "admin.users.planUpdateError": "プランを更新できません:{message}", + "admin.users.noKeys": "キーなし", + "admin.users.noKeysDesc": "このユーザーにはアクティブなAPIキーがありません。", + "admin.users.keysRevoked": "キーが取り消されました", + "admin.users.keysRevokedDesc": "{count}件のAPIキーが正常に取り消されました。", + "admin.users.revokeError": "キーを取り消せません:{message}", + "admin.users.retry": "再試行", + "admin.system.title": "システム", + "admin.system.subtitle": "システム状態の監視とリソース管理", + "admin.system.quotas": "翻訳枠", + "admin.system.resetQuotas": "月間枠をリセット", + "admin.system.resetting": "リセット中...", + "admin.system.reset": "リセット", + "admin.system.allOperational": "すべてのシステムが正常稼働中", + "admin.system.issuesDetected": "システムに問題が検出されました", + "admin.system.waitingData": "データを待機中...", + "admin.system.purging": "パージ中...", + "admin.system.clean": "クリーン", + "admin.system.purge": "パージ" +} diff --git a/frontend/src/lib/i18n/messages/ja/apiKeys.json b/frontend/src/lib/i18n/messages/ja/apiKeys.json new file mode 100644 index 0000000..4fa1611 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/apiKeys.json @@ -0,0 +1,72 @@ +{ + "apiKeys.webhook.title": "Intégration Webhook", + "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", + "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", + "apiKeys.webhook.codeParam": "webhook_url", + "apiKeys.title": "APIキー", + "apiKeys.subtitle": "翻訳APIへのプログラムアクセス用APIキーを管理します。", + "apiKeys.loading": "読み込み中...", + "apiKeys.sectionTitle": "API & 自動化", + "apiKeys.sectionDesc": "自動化ワークフロー用のAPIキーを生成・管理します", + "apiKeys.keysUsed": "{max} 個中 {total} 個使用", + "apiKeys.maxReached": "キーの上限に達しました。新しいキーを生成するには既存のキーを取り消してください。", + "apiKeys.canGenerate": "あと {count} 個のキーを生成できます", + "apiKeys.canGeneratePlural": "あと {count} 個のキーを生成できます", + "apiKeys.generateNew": "新しいキーを生成", + "apiKeys.keyRevoked": "キーが取り消されました", + "apiKeys.keyRevokedDesc": "APIキーは正常に取り消されました。", + "apiKeys.keyNotFound": "キーが見つかりません", + "apiKeys.keyNotFoundDesc": "APIキーは存在しません。既に取り消されている可能性があります。", + "apiKeys.error": "エラー", + "apiKeys.revokeError": "APIキーの取り消しに失敗しました。もう一度お試しください。", + "apiKeys.limitReached": "上限に達しました", + "apiKeys.limitReachedDesc": "APIキーは最大10個までです。新しいキーを生成するには既存のキーを取り消してください。", + "apiKeys.proRequired": "Pro機能が必要です", + "apiKeys.proRequiredDesc": "APIキーはPro機能です。アカウントをアップグレードしてください。", + "apiKeys.generateError": "APIキーの生成に失敗しました。もう一度お試しください。", + "apiKeys.upgrade.title": "APIキー", + "apiKeys.upgrade.subtitle": "APIアクセスで翻訳を自動化", + "apiKeys.upgrade.feat1": "無制限のAPIキーを生成", + "apiKeys.upgrade.feat2": "ドキュメント翻訳を自動化", + "apiKeys.upgrade.feat3": "Webhook通知", + "apiKeys.upgrade.feat4": "LLM翻訳モード", + "apiKeys.upgrade.proFeature": "APIキーは{pro}機能です。アップグレードしてAPI自動化を有効にしてください。", + "apiKeys.upgrade.pro": "Pro", + "apiKeys.upgrade.cta": "Proにアップグレード", + "apiKeys.dialog.maxTitle": "キーの上限に達しました", + "apiKeys.dialog.maxDesc": "APIキーは最大10個までです。新しいキーを生成する前に既存のキーを取り消してください。", + "apiKeys.dialog.close": "閉じる", + "apiKeys.dialog.generated": "APIキーが生成されました!", + "apiKeys.dialog.generatedDesc": "新しいAPIキーが作成されました。今すぐコピーしてください - 再度表示されることはありません。", + "apiKeys.dialog.important": "重要:", + "apiKeys.dialog.importantDesc": "このキーが表示されるのは今回のみです。安全に保管してください。", + "apiKeys.dialog.apiKey": "APIキー", + "apiKeys.dialog.name": "名前:", + "apiKeys.dialog.done": "完了", + "apiKeys.dialog.copied": "キーをコピーしました", + "apiKeys.dialog.generateTitle": "新しいAPIキーを生成", + "apiKeys.dialog.generateDesc": "翻訳APIへのプログラムアクセス用の新しいAPIキーを作成します。", + "apiKeys.dialog.keyName": "キー名(オプション)", + "apiKeys.dialog.keyNamePlaceholder": "例:本番環境、ステージング", + "apiKeys.dialog.keyNameHint": "後でこのキーを識別するためのわかりやすい名前。", + "apiKeys.dialog.nameTooLong": "名前は{max}文字以内で入力してください", + "apiKeys.dialog.nameInvalid": "名前に使用できるのは文字、数字、スペース、ハイフン、アンダースコアのみです", + "apiKeys.dialog.cancel": "キャンセル", + "apiKeys.dialog.generating": "生成中...", + "apiKeys.dialog.generate": "キーを生成", + "apiKeys.table.name": "名前", + "apiKeys.table.prefix": "プレフィックス", + "apiKeys.table.created": "作成日", + "apiKeys.table.lastUsed": "最終使用日", + "apiKeys.table.never": "未使用", + "apiKeys.table.actions": "操作", + "apiKeys.table.revoke": "取り消し", + "apiKeys.table.copyPrefix": "キーのプレフィックスをコピー", + "apiKeys.table.revokeKey": "キーを取り消し", + "apiKeys.revokeDialog.title": "APIキーを取り消し", + "apiKeys.revokeDialog.desc": "キー「{name}」を取り消してもよろしいですか?この操作は取り消せません。", + "apiKeys.revokeDialog.confirm": "はい、取り消します", + "apiKeys.revokeDialog.cancel": "キャンセル", + "apiKeys.noKeysGenerated": "キーは生成されていません", + "apiKeys.copied": "コピーしました!" +} diff --git a/frontend/src/lib/i18n/messages/ja/auth.json b/frontend/src/lib/i18n/messages/ja/auth.json new file mode 100644 index 0000000..b300370 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/auth.json @@ -0,0 +1,3 @@ +{ + "auth.brandName": "Wordly" +} diff --git a/frontend/src/lib/i18n/messages/ja/checkout.json b/frontend/src/lib/i18n/messages/ja/checkout.json new file mode 100644 index 0000000..e737cff --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/checkout.json @@ -0,0 +1,12 @@ +{ + "checkout.activating": "有効化中…", + "checkout.activatingDesc": "サブスクリプションを更新中です。しばらくお待ちください。", + "checkout.paymentConfirmed": "支払いを確認しました!", + "checkout.subscriptionActivated": "サブスクリプションが有効化されました!", + "checkout.planActivated": "{plan} プランが有効化されました!", + "checkout.redirectingToProfile": "プロフィールにリダイレクト中…", + "checkout.paymentReceived": "支払いを受領しました", + "checkout.redirecting": "リダイレクト中…", + "checkout.syncError": "同期エラー", + "checkout.networkError": "ネットワークエラー。お支払いは確認済みです — プロフィールを再読み込みしてください。" +} diff --git a/frontend/src/lib/i18n/messages/ja/common.json b/frontend/src/lib/i18n/messages/ja/common.json new file mode 100644 index 0000000..03af541 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/common.json @@ -0,0 +1,4 @@ +{ + "common.loading": "読み込み中...", + "common.backToHome": "ホームに戻る" +} diff --git a/frontend/src/lib/i18n/messages/ja/context.json b/frontend/src/lib/i18n/messages/ja/context.json new file mode 100644 index 0000000..5eba5ce --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/context.json @@ -0,0 +1,25 @@ +{ + "context.proTitle": "Pro機能", + "context.proDesc": "コンテキストとプロフェッショナル用語集はPro、Business、Enterpriseプランでご利用いただけます。ドメイン固有の指示と語彙により、より正確な翻訳が提供されます。", + "context.viewPlans": "プランを見る", + "context.title": "コンテキスト & 用語集", + "context.subtitle": "ドメイン固有の指示と語彙で翻訳品質を向上させます。", + "context.presets.title": "プロフェッショナル用語集", + "context.presets.desc": "指示と専門用語を含む完全な用語集を読み込みます", + "context.instructions.title": "コンテキスト指示", + "context.instructions.desc": "翻訳中にAIが従う指示", + "context.instructions.placeholder": "例:HVAC技術文書を翻訳します。正確な工学用語を使用してください...", + "context.glossary.title": "技術用語集", + "context.glossary.desc": "形式:source=target(1行に1つ)。プリセットで読み込んだ用語集は編集可能です。", + "context.glossary.terms": "用語集の用語数", + "context.clearAll": "すべてクリア", + "context.saving": "保存中...", + "context.save": "保存", + "context.presets.createGlossary": "用語集を作成", + "context.presets.created": "用語集を作成しました", + "context.presets.createdDesc": "用語集「{name}」を{count}件の用語で作成しました。", + "context.presets.hint": "プリセットをクリックして、専門用語の用語集を作成します。用語集セクションで管理できます。", + "context.glossary.manage": "用語集を管理", + "context.saved": "保存しました", + "context.savedDesc": "コンテキスト指示を保存しました。" +} diff --git a/frontend/src/lib/i18n/messages/ja/cookieConsent.json b/frontend/src/lib/i18n/messages/ja/cookieConsent.json new file mode 100644 index 0000000..842bded --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/cookieConsent.json @@ -0,0 +1,7 @@ +{ + "cookieConsent.title": "WordlyのCookie", + "cookieConsent.description": "アプリの動作に必要なCookieを使用します(セッション、セキュリティ、言語)。許可をいただいた場合、トラフィックの測定と製品の改善のためのオプションCookieも使用します。", + "cookieConsent.acceptAll": "すべて許可", + "cookieConsent.essentialOnly": "必要なもののみ", + "cookieConsent.learnMore": "詳細" +} diff --git a/frontend/src/lib/i18n/messages/ja/dashboard.json b/frontend/src/lib/i18n/messages/ja/dashboard.json new file mode 100644 index 0000000..1fc215d --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/dashboard.json @@ -0,0 +1,111 @@ +{ + "dashboard.nav.translate": "翻訳する", + "dashboard.nav.profile": "マイプロフィール", + "dashboard.nav.settings": "設定", + "dashboard.nav.context": "コンテキスト", + "dashboard.nav.services": "サービス", + "dashboard.nav.apiKeys": "APIキー", + "dashboard.nav.glossaries": "用語集", + "dashboard.header.title": "ダッシュボード", + "dashboard.header.subtitle": "翻訳を管理", + "dashboard.header.toggleMenu": "メニュー", + "dashboard.header.profileTitle": "マイプロフィール", + "dashboard.sidebar.theme": "テーマ", + "dashboard.sidebar.signOut": "ログアウト", + "dashboard.sidebar.backHome": "ホームに戻る", + "dashboard.sidebar.upgradeToPro": "Proにアップグレード →", + "dashboard.translate.pageTitle": "ドキュメントを翻訳", + "dashboard.translate.pageSubtitle": "ファイルをインポートして翻訳先言語を選択", + "dashboard.translate.errorNotificationTitle": "エラー", + "dashboard.translate.dropzone.uploadAria": "ファイルドロップゾーン", + "dashboard.translate.dropzone.title": "ファイルをここにドラッグ&ドロップ", + "dashboard.translate.dropzone.subtitle": "またはクリックして選択(DOCX、XLSX、PPTX、PDF)", + "dashboard.translate.dropzone.replaceFile": "ファイルを置き換え", + "dashboard.translate.language.source": "翻訳元言語", + "dashboard.translate.language.target": "翻訳先言語", + "dashboard.translate.language.loading": "言語を読み込み中…", + "dashboard.translate.language.autoDetect": "自動検出", + "dashboard.translate.language.selectPlaceholder": "選択…", + "dashboard.translate.language.loadErrorPrefix": "言語の読み込みに失敗しました", + "dashboard.translate.provider.loading": "プロバイダーを読み込み中…", + "dashboard.translate.provider.noneConfigured": "プロバイダーが設定されていません", + "dashboard.translate.provider.modelTitle": "モデル", + "dashboard.translate.provider.sectionTitle": "プロバイダー", + "dashboard.translate.provider.llmDivider": "AI・コンテキスト認識", + "dashboard.translate.provider.llmDividerPro": "AI・コンテキスト認識(Pro)", + "dashboard.translate.provider.upgrade": "Proにアップグレード", + "dashboard.translate.provider.upgradeSuffix": "AI翻訳をアンロック", + "dashboard.translate.trust.zeroRetention": "データ保持なし", + "dashboard.translate.trust.deletedAfter": "処理後にファイルを削除", + "dashboard.translate.actions.uploading": "アップロード中…", + "dashboard.translate.actions.translate": "翻訳する", + "dashboard.translate.actions.filePrefix": "ファイル:", + "dashboard.translate.actions.cancel": "キャンセル", + "dashboard.translate.actions.tryAgain": "再試行", + "dashboard.translate.steps.uploading": "ファイルをアップロード中…", + "dashboard.translate.steps.starting": "翻訳を開始中…", + "dashboard.translate.complete.title": "翻訳完了!", + "dashboard.translate.complete.descNamed": "ファイル{name}の翻訳が正常に完了しました。", + "dashboard.translate.complete.descGeneric": "ファイルの翻訳が正常に完了しました。", + "dashboard.translate.complete.downloading": "ダウンロード中…", + "dashboard.translate.complete.download": "ダウンロード", + "dashboard.translate.complete.newTranslation": "新しい翻訳", + "dashboard.translate.complete.toastOkTitle": "成功", + "dashboard.translate.complete.toastOkDesc": "{name} のダウンロードが完了しました。", + "dashboard.translate.complete.toastFailTitle": "失敗", + "dashboard.translate.complete.toastFailDesc": "翻訳に失敗しました。もう一度お試しください。", + "dashboard.translate.sourceDocument": "ソースドキュメント", + "dashboard.translate.configuration": "設定", + "dashboard.translate.translating": "翻訳中", + "dashboard.translate.liveMonitor": "ライブモニター", + "dashboard.translate.summary": "概要", + "dashboard.translate.engine": "エンジン", + "dashboard.translate.confidence": "信頼度", + "dashboard.translate.cancel": "キャンセル", + "dashboard.translate.segments": "セグメント", + "dashboard.translate.characters": "文字", + "dashboard.translate.elapsed": "経過時間", + "dashboard.translate.segPerMin": "セグ/分", + "dashboard.translate.highQuality": "高品質", + "dashboard.translate.quality": "品質", + "dashboard.translate.completed": "翻訳完了", + "dashboard.translate.replace": "置換", + "dashboard.translate.pdfMode.title": "PDF翻訳モード", + "dashboard.translate.pdfMode.preserveLayout": "レイアウト保持", + "dashboard.translate.pdfMode.textOnly": "テキストのみ", + "dashboard.translate.pdfMode.preserveLayoutDesc": "画像、表、書式を保持。シンプルなPDFに最適。", + "dashboard.translate.pdfMode.textOnlyDesc": "すべてのテキストを完璧に翻訳。レイアウト問題のないクリーンな出力。", + "dashboard.translate.pipeline.upload": "アップロード", + "dashboard.translate.pipeline.analyze": "分析", + "dashboard.translate.pipeline.translate": "翻訳", + "dashboard.translate.pipeline.rebuild": "再構築", + "dashboard.translate.pipeline.finalize": "完了", + "dashboard.translate.progress.processingFallback": "処理中…", + "dashboard.translate.progress.connectionLost": "接続が失われました。再試行中…", + "dashboard.translate.progress.failedTitle": "翻訳失敗", + "dashboard.translate.error.unexpected": "予期しないエラーが発生しました。もう一度お試しください。", + "dashboard.translate.error.noResult": "翻訳結果が得られませんでした。ドキュメントにテキストが含まれていることを確認し、再試行するか別のエンジンを選択してください。", + "dashboard.translate.error.apiKey": "APIキーが無効または不足しています。管理者に連絡してAPIキーを設定してください。", + "dashboard.translate.error.quota": "利用制限に達しました。数分後にもう一度お試しいただくか、別のエンジンを選択してください。", + "dashboard.translate.error.timeout": "翻訳サービスへの接続がタイムアウトしました。ネットワークを確認して再試行してください。", + "dashboard.translate.error.sessionExpired": "セッションが期限切れです。再試行をクリックして翻訳を再開してください。", + "dashboard.translate.error.empty": "ドキュメントが空か、翻訳可能なテキストが含まれていません(スキャンPDF画像?)。", + "dashboard.translate.error.unsupported": "サポートされていないファイル形式または破損したファイルです。", + "dashboard.translate.error.connection": "接続が切断されました。ネットワークを確認して再試行してください。", + "dashboard.translate.error.generic": "翻訳失敗:{detail}", + "dashboard.translate.error.title": "翻訳失敗", + "dashboard.translate.retry": "再翻訳", + "dashboard.translate.newFile": "新しいファイル", + "dashboard.translate.modeAI": "AIモード", + "dashboard.translate.modeClassic": "クラシックモード", + "dashboard.translate.glossaryLLMHint": "AIモードで用語集が利用可能", + "dashboard.translate.submitting": "送信中...", + "dashboard.translate.submit": "翻訳を開始", + "dashboard.translate.noFile": "先にファイルをアップロードしてください", + "dashboard.translate.noTargetLang": "翻訳先の言語を選択してください", + "dashboard.topbar.interfaceLabel": "翻訳インターフェース", + "dashboard.topbar.premiumAccess": "プレミアムアクセス", + "dashboard.checkoutSyncError": "支払いの同期エラー。", + "dashboard.networkRefresh": "ネットワークエラー。ページを更新してください。", + "dashboard.continueToTranslate": "翻訳に進む" +} diff --git a/frontend/src/lib/i18n/messages/ja/fileUploader.json b/frontend/src/lib/i18n/messages/ja/fileUploader.json new file mode 100644 index 0000000..754d66d --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/fileUploader.json @@ -0,0 +1,31 @@ +{ + "fileUploader.uploadDocument": "ドキュメントをアップロード", + "fileUploader.uploadDesc": "ファイルをドラッグ&ドロップまたはクリックして選択 (Excel, Word, PowerPoint)", + "fileUploader.dropHere": "ここにファイルをドロップ…", + "fileUploader.dragAndDrop": "ここにドキュメントをドラッグ&ドロップ", + "fileUploader.orClickBrowse": "またはクリックして参照", + "fileUploader.preview": "プレビュー", + "fileUploader.translationOptions": "翻訳オプション", + "fileUploader.configureSettings": "翻訳設定を構成する", + "fileUploader.targetLanguage": "翻訳先の言語", + "fileUploader.selectLanguage": "言語を選択", + "fileUploader.translationProvider": "翻訳プロバイダー", + "fileUploader.selectProvider": "プロバイダーを選択", + "fileUploader.advancedOptions": "詳細オプション", + "fileUploader.translateImages": "画像を翻訳", + "fileUploader.translating": "翻訳中…", + "fileUploader.translateDocument": "ドキュメントを翻訳", + "fileUploader.processing": "処理中…", + "fileUploader.translationError": "翻訳エラー", + "fileUploader.translationComplete": "翻訳完了!", + "fileUploader.translationCompleteDesc": "書式をすべて保持したまま、ドキュメントの翻訳が完了しました。", + "fileUploader.download": "翻訳済みドキュメントをダウンロード", + "fileUploader.webgpuUnsupported": "このブラウザは WebGPU に対応していません。Chrome 113+ または Edge 113+ を使用してください。", + "fileUploader.webllmNotLoaded": "WebLLM モデルが読み込まれていません。設定 > 翻訳サービスからモデルを読み込んでください。", + "fileUploader.extracting": "ドキュメントからテキストを抽出中…", + "fileUploader.noTranslatable": "ドキュメントに翻訳可能なテキストが見つかりません", + "fileUploader.foundTexts": "{count} 件の翻訳対象テキストが見つかりました", + "fileUploader.translatingItem": "翻訳中 {current}/{total}: 「{preview}」", + "fileUploader.reconstructing": "ドキュメントを再構築中…", + "fileUploader.translatingLocally": "WebLLM でローカル翻訳中…" +} diff --git a/frontend/src/lib/i18n/messages/ja/forgotPassword.json b/frontend/src/lib/i18n/messages/ja/forgotPassword.json new file mode 100644 index 0000000..0ac67c8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/forgotPassword.json @@ -0,0 +1,14 @@ +{ + "forgotPassword.enterEmail": "Please enter your email address", + "forgotPassword.error": "An error occurred", + "forgotPassword.title": "Forgot Password", + "forgotPassword.checkEmail": "Check your inbox", + "forgotPassword.subtitle": "Enter your email to receive a reset link", + "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", + "forgotPassword.emailLabel": "Email address", + "forgotPassword.emailPlaceholder": "you@example.com", + "forgotPassword.sending": "Sending...", + "forgotPassword.sendLink": "Send reset link", + "forgotPassword.backToLogin": "Back to login", + "forgotPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/ja/glossaries.json b/frontend/src/lib/i18n/messages/ja/glossaries.json new file mode 100644 index 0000000..7013ae7 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/glossaries.json @@ -0,0 +1,189 @@ +{ + "glossaries.yourGlossaries": "あなたの用語集", + "glossaries.title": "用語集とコンテキスト", + "glossaries.description": "用語集とコンテキスト指示を管理して、より正確な翻訳を実現します。", + "glossaries.createNew": "新規作成", + "glossaries.empty": "用語集はまだありません", + "glossaries.emptyDesc": "最初の用語集を作成するか、上のプロフェッショナルプリセットを読み込んでください", + "glossaries.defineTerms": "用語", + "glossaries.aboutTitle": "用語集について", + "glossaries.aboutDesc": "用語集を使用すると、特定の用語の正確な翻訳を定義できます。翻訳時に用語集の用語が使用され、一貫した正確な翻訳が保証されます。", + "glossaries.aboutFormat": "各用語にはソース語と複数言語の翻訳があります。翻訳ページで用語集を選択して適用してください。", + "glossaries.toast.created": "用語集を作成しました", + "glossaries.toast.createdDesc": "用語集「{name}」を作成しました。", + "glossaries.toast.imported": "用語集をインポートしました", + "glossaries.toast.importedDesc": "用語集「{name}」をインポートしました。", + "glossaries.toast.updated": "用語集を更新しました", + "glossaries.toast.updatedDesc": "用語集「{name}」を更新しました。", + "glossaries.toast.deleted": "用語集を削除しました", + "glossaries.toast.deletedDesc": "用語集を削除しました。", + "glossaries.toast.error": "エラー", + "glossaries.toast.errorCreate": "用語集の作成に失敗しました", + "glossaries.toast.errorImport": "用語集のインポートに失敗しました", + "glossaries.toast.errorUpdate": "用語集の更新に失敗しました", + "glossaries.toast.errorDelete": "用語集の削除に失敗しました", + "glossaries.dialog.title": "新しい用語集", + "glossaries.dialog.description": "翻訳用の用語集を作成", + "glossaries.dialog.nameLabel": "名前", + "glossaries.dialog.namePlaceholder": "マイ用語集", + "glossaries.dialog.tabTemplates": "テンプレート", + "glossaries.dialog.tabFile": "ファイル", + "glossaries.dialog.tabManual": "手動", + "glossaries.dialog.cancel": "キャンセル", + "glossaries.dialog.creating": "作成中…", + "glossaries.dialog.importing": "インポート中…", + "glossaries.dialog.importBtn": "インポート", + "glossaries.dialog.selectPrompt": "選択", + "glossaries.dialog.createBtn": "作成", + "glossaries.dialog.createEmpty": "空で作成", + "glossaries.dialog.terms": "件", + "glossaries.dialog.templatesDesc": "定義済みテンプレートを選択", + "glossaries.dialog.templatesEmpty": "利用可能なテンプレートがありません", + "glossaries.dialog.dropTitle": "CSVファイルをここにドラッグ", + "glossaries.dialog.dropOr": "または", + "glossaries.dialog.dropFormats": "CSV、TSV、TXT", + "glossaries.termEditor.addTerm": "用語を追加", + "glossaries.termEditor.maxReached": "用語集ごとに最大 {max} 語に達しました。", + "glossaries.dialog.formatTitle": "形式", + "glossaries.dialog.formatDesc": "原文,訳文(1行につき1組)", + "glossaries.dialog.formatNote": "ヘッダーが検出された場合、最初の行はスキップされます", + "glossaries.dialog.errorFormat": "サポートされていない形式", + "glossaries.dialog.errorSize": "ファイルが大きすぎます", + "glossaries.dialog.errorEmpty": "空のファイル", + "glossaries.dialog.errorRead": "読み取りエラー", + "glossaries.dialog.parsing": "解析中…", + "glossaries.dialog.termsImported": "件インポート済み", + "glossaries.dialog.changeFile": "ファイルを変更", + "glossaries.dialog.retry": "再試行", + "glossaries.edit.title": "Modifier le glossaire", + "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", + "glossaries.edit.nameLabel": "Nom du glossaire", + "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", + "glossaries.edit.sourceLang": "Langue source", + "glossaries.edit.targetLang": "Langue cible", + "glossaries.edit.termsLabel": "Termes ({count} valides)", + "glossaries.edit.exportCsv": "Exporter CSV", + "glossaries.edit.importCsv": "Importer CSV", + "glossaries.edit.cancel": "Annuler", + "glossaries.edit.saving": "Enregistrement...", + "glossaries.edit.saveChanges": "Enregistrer les modifications", + "glossaries.edit.importFailedTitle": "Échec de l'importation", + "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", + "glossaries.edit.importSuccessTitle": "Importation réussie", + "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", + "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", + "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", + "glossaries.delete.title": "Supprimer le glossaire", + "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", + "glossaries.delete.warning": "Cette action est irréversible", + "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", + "glossaries.delete.cancel": "Annuler", + "glossaries.delete.deleting": "Suppression...", + "glossaries.delete.deleteBtn": "Supprimer", + "glossaries.upgrade.title": "Glossaires", + "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", + "glossaries.upgrade.feature1": "Créez plusieurs glossaires", + "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", + "glossaries.upgrade.feature3": "Importez/exportez via CSV", + "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", + "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", + "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", + "glossaries.upgrade.proLabel": "Pro", + "glossaries.upgrade.upgradeBtn": "Passer à Pro", + "glossaries.loading": "Chargement...", + "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", + "glossaries.howItWorks.step1Title": "Configurez ici", + "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", + "glossaries.howItWorks.step2Title": "Activez dans Traduire", + "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", + "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", + "glossaries.howItWorks.goToTranslate": "Aller à Traduire", + "glossaries.status.unsaved": "Non enregistré", + "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", + "glossaries.status.inactive": "Inactif", + "glossaries.instructions.whatForBold": "À quoi ça sert ?", + "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", + "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", + "glossaries.instructions.charCount": "{count} caractères", + "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", + "glossaries.instructions.clearAll": "Tout effacer", + "glossaries.instructions.saving": "Enregistrement…", + "glossaries.instructions.saved": "Enregistré", + "glossaries.presets.whatForBold": "À quoi ça sert ?", + "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", + "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", + "glossaries.presets.creating": "Création…", + "glossaries.presets.alreadyImported": "Déjà importé", + "glossaries.presets.it.title": "IT / Logiciel", + "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", + "glossaries.presets.legal.title": "Juridique / Contrats", + "glossaries.presets.legal.desc": "Droit des affaires, contentieux", + "glossaries.presets.medical.title": "Médical / Santé", + "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", + "glossaries.presets.finance.title": "Finance / Comptabilité", + "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", + "glossaries.presets.marketing.title": "Marketing / Publicité", + "glossaries.presets.marketing.desc": "Digital, branding, analytics", + "glossaries.presets.hr.title": "RH / Ressources Humaines", + "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", + "glossaries.presets.scientific.title": "Scientifique / Recherche", + "glossaries.presets.scientific.desc": "Publications, thèses, articles", + "glossaries.presets.ecommerce.title": "E-commerce / Vente", + "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", + "glossaries.grid.title": "Vos", + "glossaries.grid.titleHighlight": "glossaires", + "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", + "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", + "glossaries.grid.activeTranslation": "Traduction active :", + "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", + "glossaries.badge.compatible": "Compatible", + "glossaries.badge.otherTarget": "Autre cible", + "glossaries.card.editTerms": "Modifier les termes", + "glossaries.card.created": "作成日", + "glossaries.card.term": "用語", + "glossaries.card.delete": "Supprimer", + "glossaries.grid.searchPlaceholder": "Search a glossary…", + "glossaries.grid.noResults": "No results for this search.", + "glossaries.detail.backToList": "Back to glossaries", + "glossaries.detail.save": "Save", + "glossaries.detail.savedTitle": "Saved", + "glossaries.detail.savedDesc": "The glossary has been updated.", + "glossaries.detail.settingsTitle": "Settings", + "glossaries.detail.sourceLang": "Source language", + "glossaries.detail.targetLang": "Target language", + "glossaries.detail.termsTitle": "Terms", + "glossaries.detail.terms": "terms", + "glossaries.detail.searchTerms": "Filter…", + "glossaries.detail.noTerms": "No terms yet.", + "glossaries.detail.addFirstTerm": "Add the first term", + "glossaries.detail.addTerm": "Add a term", + "glossaries.detail.maxReached": "Maximum limit reached", + "glossaries.detail.source": "Source", + "glossaries.detail.target": "Target", + "glossaries.detail.sourcePlaceholder": "source term", + "glossaries.detail.targetPlaceholder": "target term", + "glossaries.detail.csvTitle": "CSV", + "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", + "glossaries.detail.export": "Export", + "glossaries.detail.import": "Import", + "glossaries.detail.dangerTitle": "Danger zone", + "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", + "glossaries.detail.deleteGlossary": "Delete this glossary", + "glossaries.detail.confirmDelete": "Confirm deletion?", + "glossaries.detail.confirm": "Confirm", + "glossaries.detail.cancel": "Cancel", + "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", + "glossaries.detail.sourceLocked": "fixed", + "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", + "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", + "glossaries.detail.notFoundTitle": "Glossary not found", + "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", + "glossaries.detail.maxTermsTitle": "Limit reached", + "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", + "glossaries.detail.importEmptyTitle": "Empty file", + "glossaries.detail.importEmptyDesc": "No terms detected in this file.", + "glossaries.detail.importedTitle": "Imported", + "glossaries.detail.importedDesc": "{count} terms imported.", + "glossaries.detail.importErrorTitle": "Read error", + "glossaries.detail.importErrorDesc": "Unable to read the file." +} diff --git a/frontend/src/lib/i18n/messages/ja/index.ts b/frontend/src/lib/i18n/messages/ja/index.ts new file mode 100644 index 0000000..7fa88b2 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/index.ts @@ -0,0 +1,60 @@ +// Auto-generated by scripts/generate_i18n_index.py +// Merges all namespace JSON files for locale "ja". + +import admin from "./admin.json"; +import apiKeys from "./apiKeys.json"; +import auth from "./auth.json"; +import checkout from "./checkout.json"; +import common from "./common.json"; +import context from "./context.json"; +import cookieConsent from "./cookieConsent.json"; +import dashboard from "./dashboard.json"; +import fileUploader from "./fileUploader.json"; +import forgotPassword from "./forgotPassword.json"; +import glossaries from "./glossaries.json"; +import landing from "./landing.json"; +import langSelector from "./langSelector.json"; +import layout from "./layout.json"; +import login from "./login.json"; +import memento from "./memento.json"; +import pricing from "./pricing.json"; +import profile from "./profile.json"; +import providerSelector from "./providerSelector.json"; +import providerTheme from "./providerTheme.json"; +import register from "./register.json"; +import resetPassword from "./resetPassword.json"; +import services from "./services.json"; +import settings from "./settings.json"; +import translate from "./translate.json"; +import translateComplete from "./translateComplete.json"; + +const messages: Record = { + ...admin, + ...apiKeys, + ...auth, + ...checkout, + ...common, + ...context, + ...cookieConsent, + ...dashboard, + ...fileUploader, + ...forgotPassword, + ...glossaries, + ...landing, + ...langSelector, + ...layout, + ...login, + ...memento, + ...pricing, + ...profile, + ...providerSelector, + ...providerTheme, + ...register, + ...resetPassword, + ...services, + ...settings, + ...translate, + ...translateComplete, +}; + +export default messages; diff --git a/frontend/src/lib/i18n/messages/ja/landing.json b/frontend/src/lib/i18n/messages/ja/landing.json new file mode 100644 index 0000000..9f64ae6 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/landing.json @@ -0,0 +1,146 @@ +{ + "landing.nav.why": "選ばれる理由", + "landing.nav.formats": "対応形式", + "landing.nav.pricing": "料金プラン", + "landing.nav.login": "ログイン", + "landing.nav.startFree": "無料で始める", + "landing.hero.tag": "プロフェッショナル文書AI", + "landing.hero.titleLine1": "ドキュメントを翻訳。", + "landing.hero.titleLine2": "フォーマットは完璧に保持。", + "landing.hero.description": "SmartArt、グラフ、目次、図形、複雑なレイアウトを元のまま保持する唯一の翻訳ツール。", + "landing.hero.ctaMain": "無料で始める — 月2ファイル", + "landing.hero.ctaSec": "プランを見る", + "landing.hero.deleted": "ファイルは60分後に削除", + "landing.hero.noHidden": "隠し料金なし", + "landing.hero.preview": "支払い前にプレビュー", + "landing.hero.formattedOk": "フォーマットOK", + "landing.hero.aiActive": "AI翻訳アクティブ", + "landing.steps.title": "使い方", + "landing.steps.subtitle": "3つのステップ。フォーマット損失ゼロ。", + "landing.steps.step1.num": "01", + "landing.steps.step1.title": "ファイルをアップロード", + "landing.steps.step1.desc": "Excel、Word、PowerPoint、PDFファイルをドラッグ&ドロップ。", + "landing.steps.step2.num": "02", + "landing.steps.step2.title": "言語とエンジンを選択", + "landing.steps.step2.desc": "翻訳先の言語とエンジンを選択 — クラシックまたはコンテキスト対応AI。", + "landing.steps.step3.num": "03", + "landing.steps.step3.title": "結果をダウンロード", + "landing.steps.step3.desc": "元の文書と同じフォーマットの翻訳文書を取得。", + "landing.features.tag": "AI翻訳エンジン", + "landing.features.title": "あなたの専門性を理解する翻訳", + "landing.features.description": "AIモデルがコンテキストを分析し、専門用語を尊重し、画像内のテキストまで翻訳します。", + "landing.features.context.title": "業界コンテキスト", + "landing.features.context.desc": "業界を説明すれば、汎用的でない、最適化された翻訳を取得できます。", + "landing.features.glossary.title": "業界用語集", + "landing.features.glossary.desc": "専門用語を定義。CTAは「Call To Action」ではなく「空調処理ユニット」のまま。", + "landing.features.vision.title": "画像認識", + "landing.features.vision.desc": "画像、図、グラフに埋め込まれたテキストを検出して翻訳。", + "landing.features.demo.source": "原文(FR)", + "landing.features.demo.google": "Google翻訳", + "landing.features.demo.ours": "当社のAI", + "landing.layout.title": "あなたのフォーマット、", + "landing.layout.title2": "完璧に保持", + "landing.layout.subtitle": "他の翻訳ツールはレイアウトを崩します。私たちは違います。", + "landing.layout.p1.title": "SmartArtと図", + "landing.layout.p1.desc": "組織図、フローチャート、階層図 — すべて同一に翻訳。", + "landing.layout.p2.title": "目次", + "landing.layout.p2.desc": "目次のエントリ、ページ番号、相互参照を正しく更新。", + "landing.layout.p3.title": "グラフとチャート", + "landing.layout.p3.desc": "タイトル、軸ラベル、凡例、系列名 — すべて翻訳。", + "landing.layout.p4.title": "図形とテキストボックス", + "landing.layout.p4.desc": "四角形、角丸ブロック、吹き出し — すべてローカライズ。", + "landing.layout.p5.title": "ヘッダーとフッター", + "landing.layout.p5.desc": "ヘッダー、フッター、脚注を確実に翻訳。", + "landing.layout.p6.title": "130以上の言語", + "landing.layout.p6.desc": "Google翻訳、DeepL、プロフェッショナルグレードのAIエンジン。", + "landing.formats.title": "すべての形式、", + "landing.formats.title2": "すべての要素", + "landing.formats.subtitle": "他社が見落とす部分も翻訳。ビジネスに完璧なドキュメントを。", + "landing.formats.word.name": "Word", + "landing.formats.word.i1": "段落と見出し", + "landing.formats.word.i2": "表とグラフ", + "landing.formats.word.i3": "SmartArt図", + "landing.formats.word.i4": "目次", + "landing.formats.word.i5": "ヘッダーとフッター", + "landing.formats.word.i6": "図形とテキストボックス", + "landing.formats.word.i7": "脚注と文末脚注", + "landing.formats.excel.name": "Excel", + "landing.formats.excel.i1": "セルの値", + "landing.formats.excel.i2": "シート名", + "landing.formats.excel.i3": "グラフとラベル", + "landing.formats.excel.i4": "ヘッダーとフッター", + "landing.formats.excel.i5": "結合セルを保持", + "landing.formats.pptx.name": "PowerPoint", + "landing.formats.pptx.i1": "スライドテキストとノート", + "landing.formats.pptx.i2": "グラフと図", + "landing.formats.pptx.i3": "図形とテキストボックス", + "landing.formats.pptx.i4": "マスターレイアウト", + "landing.formats.pptx.i5": "アニメーションを保持", + "landing.formats.pdf.name": "PDF", + "landing.formats.pdf.i1": "テキストベースPDF", + "landing.formats.pdf.i2": "レイアウトを保持", + "landing.formats.pdf.i3": "画像を元の位置に保持", + "landing.formats.pdf.i4": "表を維持", + "landing.formats.pdf.i5": "DOCXまたはPDFで出力", + "landing.pricing.title": "シンプルで透明な料金", + "landing.pricing.subtitle": "見たままの価格。隠し料金なし。", + "landing.pricing.monthly": "月額", + "landing.pricing.annual": "年額", + "landing.pricing.bestValue": "一番人気", + "landing.pricing.month": "/月", + "landing.pricing.footer": "表示価格がお支払いいただく金額です。翻訳後の追加料金は一切ありません。", + "landing.pricing.starter.name": "Starter", + "landing.pricing.starter.desc": "個人や小規模プロジェクト向け", + "landing.pricing.starter.f1": "月50ドキュメント", + "landing.pricing.starter.f2": "1ドキュメント最大50ページ", + "landing.pricing.starter.f3": "Google翻訳 + DeepL", + "landing.pricing.starter.f4": "最大10 MBのファイル", + "landing.pricing.starter.cta": "始める", + "landing.pricing.pro.name": "Pro", + "landing.pricing.pro.desc": "プロフェッショナル向け", + "landing.pricing.pro.f1": "月200ドキュメント", + "landing.pricing.pro.f2": "1ドキュメント最大200ページ", + "landing.pricing.pro.f3": "AI翻訳", + "landing.pricing.pro.f4": "Google + DeepL込み", + "landing.pricing.pro.f5": "カスタム用語集とプロンプト", + "landing.pricing.pro.f6": "優先サポート", + "landing.pricing.pro.cta": "Proを試す", + "landing.pricing.business.name": "ビジネス", + "landing.pricing.business.desc": "大量処理が必要なチーム向け", + "landing.pricing.business.f1": "月1,000ドキュメント", + "landing.pricing.business.f2": "1ドキュメント最大500ページ", + "landing.pricing.business.f3": "プレミアムAI(Claude)", + "landing.pricing.business.f4": "全プロバイダー + API", + "landing.pricing.business.f5": "Webhookと自動化", + "landing.pricing.business.f6": "チームシート5席", + "landing.pricing.business.cta": "お問い合わせ", + "landing.cta.title": "30秒で翻訳を開始", + "landing.cta.subtitle": "クレジットカード不要。今すぐ無料でお試しください。", + "landing.cta.button": "無料アカウント作成", + "landing.cta.secure": "AES-256暗号化で保護", + "landing.footer.desc": "インテリジェントな文書翻訳のエキスパート。レイアウトの芸術とコンテキストAIの科学を融合。", + "landing.footer.product": "製品", + "landing.footer.resources": "リソース", + "landing.footer.legal": "法務", + "landing.footer.rights": "© 2026 Wordly.art — All rights reserved.", + "landing.hero.contextEngine": "翻訳検出:HVACシステムの技術保守用語...", + "landing.hero.liveAnalysis": "リアルタイム分析", + "landing.hero.termsDetected": "件の用語を検出", + "landing.steps.process": "プロセス", + "landing.translate.newProject": "新規プロジェクト", + "landing.translate.title": "ドキュメントを翻訳", + "landing.translate.subtitle": "ファイルをインポートして翻訳先言語を選択", + "landing.translate.sourceDocument": "ソースドキュメント", + "landing.translate.configuration": "設定", + "landing.translate.sourceLang": "翻訳元言語", + "landing.translate.targetLang": "翻訳先言語", + "landing.translate.provider": "プロバイダー", + "landing.translate.startTranslation": "翻訳を開始", + "landing.translate.zeroRetention": "ゼロ保持", + "landing.translate.filesDeleted": "処理後にファイルを削除", + "landing.translate.dropHere": "ここにドラッグ&ドロップ", + "landing.translate.supportedFormats": "DOCX, XLSX, PPTX, PDFファイル対応", + "landing.translate.aiAnalysis": "AI分析アクティブ", + "landing.translate.processing": "処理中", + "landing.translate.preservingLayout": "レイアウトを保持しています" +} diff --git a/frontend/src/lib/i18n/messages/ja/langSelector.json b/frontend/src/lib/i18n/messages/ja/langSelector.json new file mode 100644 index 0000000..5d40243 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/langSelector.json @@ -0,0 +1,7 @@ +{ + "langSelector.search": "検索…", + "langSelector.noResults": "結果なし", + "langSelector.source": "翻訳元", + "langSelector.target": "翻訳先", + "langSelector.swap": "入れ替え" +} diff --git a/frontend/src/lib/i18n/messages/ja/layout.json b/frontend/src/lib/i18n/messages/ja/layout.json new file mode 100644 index 0000000..f683299 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/layout.json @@ -0,0 +1,5 @@ +{ + "layout.nav.apiAccess": "API アクセス", + "layout.footer.terms": "利用規約", + "layout.footer.privacy": "プライバシー" +} diff --git a/frontend/src/lib/i18n/messages/ja/login.json b/frontend/src/lib/i18n/messages/ja/login.json new file mode 100644 index 0000000..2fa3962 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/login.json @@ -0,0 +1,16 @@ +{ + "login.signInToContinue": "Sign in to continue translating", + "login.email": "Email", + "login.emailPlaceholder": "you@example.com", + "login.password": "Password", + "login.forgotPassword": "Forgot password?", + "login.passwordPlaceholder": "••••••••", + "login.signingIn": "Signing in...", + "login.signIn": "Sign In", + "login.noAccount": "Don't have an account?", + "login.signUpFree": "Sign up for free", + "login.orContinueWith": "またはメールで続行", + "login.google.connecting": "接続中…", + "login.google.errorGeneric": "Google ログインでエラーが発生しました。", + "login.google.errorFailed": "Google ログインに失敗しました。もう一度お試しください。" +} diff --git a/frontend/src/lib/i18n/messages/ja/memento.json b/frontend/src/lib/i18n/messages/ja/memento.json new file mode 100644 index 0000000..1b23812 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/memento.json @@ -0,0 +1,6 @@ +{ + "memento.title": "Momentoを発見", + "memento.slogan": "Momentoは単なるメモアプリではありません。6つのAIエージェントと高度なセマンティック検索を使用して、アイデアをリアルタイムで接続、分析、発展させるインテリジェントなエコシステムです。", + "memento.ctaFree": "無料で始める", + "memento.ctaMore": "詳しく見る" +} diff --git a/frontend/src/lib/i18n/messages/ja/pricing.json b/frontend/src/lib/i18n/messages/ja/pricing.json new file mode 100644 index 0000000..b1863c2 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/pricing.json @@ -0,0 +1,151 @@ +{ + "pricing.nav.back": "戻る", + "pricing.nav.home": "ホーム", + "pricing.nav.mySubscription": "マイサブスクリプション", + "pricing.header.badge": "AIモデル更新 — 2026年3月", + "pricing.header.title": "あらゆるニーズに応えるプラン", + "pricing.header.subtitle": "Word、Excel、PowerPointドキュメントを元のレイアウトを保持したまま翻訳。APIキー不要。", + "pricing.billing.monthly": "月額", + "pricing.billing.yearly": "年額", + "pricing.plans.free.name": "無料", + "pricing.plans.starter.name": "Starter", + "pricing.plans.pro.name": "Pro", + "pricing.plans.business.name": "Business", + "pricing.plans.enterprise.name": "Enterprise", + "pricing.plans.free.description": "アプリを試すのに最適", + "pricing.plans.starter.description": "個人や小規模プロジェクト向け", + "pricing.plans.pro.description": "プロフェッショナルや成長中のチーム向け", + "pricing.plans.business.description": "チームや組織向け", + "pricing.plans.enterprise.description": "大規模組織向けカスタムソリューション", + "pricing.plans.pro.highlight": "一番人気", + "pricing.plans.pro.badge": "人気No.1", + "pricing.plans.enterprise.badge": "要相談", + "pricing.plans.free.feat1": "月5ドキュメント", + "pricing.plans.free.feat2": "1ドキュメントあたり最大15ページ", + "pricing.plans.free.feat3": "Google翻訳付き", + "pricing.plans.free.feat4": "全言語対応(130+)", + "pricing.plans.free.feat5": "コミュニティサポート", + "pricing.plans.starter.feat1": "月50ドキュメント", + "pricing.plans.starter.feat2": "1ドキュメントあたり最大50ページ", + "pricing.plans.starter.feat3": "Google翻訳 + DeepL", + "pricing.plans.starter.feat4": "最大10 MBのファイル", + "pricing.plans.starter.feat5": "メールサポート", + "pricing.plans.starter.feat6": "30日間の履歴", + "pricing.plans.pro.feat1": "月200ドキュメント", + "pricing.plans.pro.feat2": "1ドキュメントあたり最大200ページ", + "pricing.plans.pro.feat3": "Essential AI翻訳", + "pricing.plans.pro.feat4": "Google翻訳 + DeepL", + "pricing.plans.pro.feat5": "最大25 MBのファイル", + "pricing.plans.pro.feat6": "カスタム用語集", + "pricing.plans.pro.feat7": "優先サポート", + "pricing.plans.pro.feat8": "90日間の履歴", + "pricing.plans.business.feat1": "月1,000ドキュメント", + "pricing.plans.business.feat2": "1ドキュメントあたり最大500ページ", + "pricing.plans.business.feat3": "エッセンシャル + プレミアムAI(Claude Haiku)", + "pricing.plans.business.feat4": "全翻訳プロバイダー", + "pricing.plans.business.feat5": "最大50 MBのファイル", + "pricing.plans.business.feat6": "APIアクセス(月10,000コール)", + "pricing.plans.business.feat7": "通知Webhook", + "pricing.plans.business.feat8": "専任サポート", + "pricing.plans.business.feat9": "1年間の履歴", + "pricing.plans.business.feat10": "高度な分析", + "pricing.plans.enterprise.feat1": "無制限ドキュメント", + "pricing.plans.enterprise.feat2": "全AIモデル(GPT-5、Claude Opus 4.6…)", + "pricing.plans.enterprise.feat3": "オンプレミスまたは専用クラウド展開", + "pricing.plans.enterprise.feat4": "99.9% SLA保証", + "pricing.plans.enterprise.feat5": "24/7専任サポート", + "pricing.plans.enterprise.feat6": "ホワイトラベル", + "pricing.plans.enterprise.feat7": "無制限チーム", + "pricing.plans.enterprise.feat8": "カスタム連携", + "pricing.card.onRequest": "要相談", + "pricing.card.free": "無料", + "pricing.card.perMonth": "/月", + "pricing.card.billedYearly": "年額 {price} € 請求", + "pricing.card.documents": "ドキュメント", + "pricing.card.pagesMax": "最大ページ数", + "pricing.card.aiTranslation": "AI翻訳", + "pricing.card.unlimited": "無制限", + "pricing.card.perMonthStat": "/ 月", + "pricing.card.perDoc": "p / doc", + "pricing.card.aiEssential": "エッセンシャル", + "pricing.card.aiEssentialPremium": "エッセンシャル + プレミアム", + "pricing.card.aiCustom": "カスタム", + "pricing.card.myPlan": "現在のプラン", + "pricing.card.managePlan": "プランを管理", + "pricing.card.startFree": "無料で始める", + "pricing.card.contactUs": "お問い合わせ", + "pricing.card.choosePlan": "このプランを選択", + "pricing.card.processing": "処理中…", + "pricing.comparison.title": "詳細な比較", + "pricing.comparison.subtitle": "各プランに含まれるすべての機能", + "pricing.comparison.feature": "機能", + "pricing.comparison.docsPerMonth": "ドキュメント / 月", + "pricing.comparison.pagesMaxPerDoc": "最大ページ数 / ドキュメント", + "pricing.comparison.maxFileSize": "最大ファイルサイズ", + "pricing.comparison.googleTranslation": "Google翻訳", + "pricing.comparison.deepl": "DeepL", + "pricing.comparison.aiEssential": "エッセンシャルAI翻訳", + "pricing.comparison.aiPremium": "プレミアムAI翻訳", + "pricing.comparison.apiAccess": "APIアクセス", + "pricing.comparison.priorityProcessing": "優先処理", + "pricing.comparison.support": "サポート", + "pricing.comparison.support.community": "コミュニティ", + "pricing.comparison.support.email": "メール", + "pricing.comparison.support.priority": "優先", + "pricing.comparison.support.dedicated": "専任", + "pricing.comparison.mb": "MB", + "pricing.credits.title": "追加クレジット", + "pricing.credits.subtitle": "もっと必要ですか?サブスクリプションなしでクレジットを個別購入。", + "pricing.credits.perPage": "1クレジット = 1翻訳ページ。", + "pricing.credits.bestValue": "最もお得", + "pricing.credits.unit": "クレジット", + "pricing.credits.centsPerCredit": "セント / クレジット", + "pricing.credits.buy": "購入", + "pricing.trust.encryption.title": "エンドツーエンド暗号化", + "pricing.trust.encryption.sub": "TLS 1.3 + AES-256(保存時)", + "pricing.trust.languages.title": "130+言語", + "pricing.trust.languages.sub": "アラビア語、ペルシャ語、ヘブライ語(RTL)を含む", + "pricing.trust.parallel.title": "並列処理", + "pricing.trust.parallel.sub": "超高速マルチスレッドAI", + "pricing.trust.availability.title": "24/7利用可能", + "pricing.trust.availability.sub": "99.9%稼働率保証", + "pricing.aiModels.title": "AIモデル一覧 — 2026年3月", + "pricing.aiModels.essential.title": "エッセンシャルAI翻訳", + "pricing.aiModels.essential.plan": "Proプラン", + "pricing.aiModels.essential.descPrefix": "ベース:", + "pricing.aiModels.essential.descSuffix": "— 2026年で最も費用対効果の高いAIモデル。フロンティアモデルと同等の品質をわずかなコストで実現。", + "pricing.aiModels.essential.modelName": "Essential AIモデル", + "pricing.aiModels.essential.context": "163Kトークンのコンテキスト", + "pricing.aiModels.essential.value": "優れた費用対効果", + "pricing.aiModels.premium.title": "プレミアムAI翻訳", + "pricing.aiModels.premium.plan": "Businessプラン", + "pricing.aiModels.premium.descPrefix": "ベース:", + "pricing.aiModels.premium.descSuffix": "(Anthropic社製)— 法務、医療、複雑な技術文書に高精度。", + "pricing.aiModels.premium.context": "200Kトークンのコンテキスト", + "pricing.aiModels.premium.precision": "最高精度", + "pricing.faq.title": "よくある質問", + "pricing.faq.q1": "いつでもプランを変更できますか?", + "pricing.faq.a1": "はい。アップグレードは即時反映され、日割り計算されます。ダウングレードは現在の期間の終了時に適用されます。", + "pricing.faq.q2": "「エッセンシャルAI翻訳」とは何ですか?", + "pricing.faq.a2": "独自のAIエンジンです。ドキュメントの文脈を理解し、レイアウトを保持し、技術用語を従来の翻訳よりはるかに適切に処理します。", + "pricing.faq.q3": "エッセンシャルAIとプレミアムAIの違いは何ですか?", + "pricing.faq.a3": "Essential AIは最適化されたモデルを使用しています(コストパフォーマンスに優れています)。Premium AIはAnthropicのClaude 3.5 Haikuを使用し、法的、医学的、複雑な技術文書により正確です。", + "pricing.faq.q4": "翻訳後もドキュメントは保存されますか?", + "pricing.faq.a4": "翻訳済みファイルはプランに応じて利用可能です(Starter 30日、Pro 90日、Business 1年)。保存時および通信時は暗号化されています。", + "pricing.faq.q5": "月間枠を超えた場合はどうなりますか?", + "pricing.faq.a5": "追加クレジットを個別購入するか、プランをアップグレードできます。使用量が80%に達すると通知されます。", + "pricing.faq.q6": "有料プランの無料試用はありますか?", + "pricing.faq.a6": "無料プランは永続的でクレジットカード不要です。ProおよびBusinessプランについては、14日間のトライアルをご希望の場合はお問い合わせください。", + "pricing.faq.q7": "対応ファイル形式を教えてください。", + "pricing.faq.a7": "Word(.docx)、Excel(.xlsx/.xls)、PowerPoint(.pptx)、および近日PDF対応予定。すべてのプランで同じ形式に対応しています。", + "pricing.cta.title": "始める準備はできましたか?", + "pricing.cta.subtitle": "クレジットカード不要で無料開始。必要に応じてアップグレード。", + "pricing.cta.createAccount": "無料アカウント作成", + "pricing.cta.login": "ログイン", + "pricing.toast.demo": "デモモード — Stripeはまだ設定されていません。本番環境では、{planId}プランを有効化するための支払いページにリダイレクトされます。", + "pricing.toast.networkError": "ネットワークエラー。もう一度お試しください。", + "pricing.toast.paymentError": "支払いの作成中にエラーが発生しました。", + "pricing.dashboard": "ダッシュボード", + "pricing.okSymbol": "✓", + "pricing.errSymbol": "✕" +} diff --git a/frontend/src/lib/i18n/messages/ja/profile.json b/frontend/src/lib/i18n/messages/ja/profile.json new file mode 100644 index 0000000..f410996 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/profile.json @@ -0,0 +1,58 @@ +{ + "profile.header.title": "マイプロフィール", + "profile.header.subtitle": "アカウントと設定を管理します。", + "profile.tabs.account": "アカウント", + "profile.tabs.subscription": "サブスクリプション", + "profile.tabs.preferences": "設定", + "profile.account.user": "ユーザー", + "profile.account.memberSince": "登録日", + "profile.plan.label": "プラン", + "profile.plan.free": "Free", + "profile.plan.starter": "Starter", + "profile.plan.pro": "Pro", + "profile.plan.business": "Business", + "profile.plan.enterprise": "Enterprise", + "profile.plan.pricePerMonth": "{price} €/月", + "profile.subscription.canceling": "キャンセル中", + "profile.subscription.active": "有効", + "profile.subscription.unknown": "不明", + "profile.subscription.accessUntil": "アクセス可能期限", + "profile.subscription.renewalOn": "次回更新日", + "profile.subscription.upgradePlan": "有料プランにアップグレード", + "profile.subscription.changePlan": "プランを変更", + "profile.subscription.manageBilling": "支払い管理", + "profile.subscription.billingUnavailable": "支払いポータルは利用できません。", + "profile.subscription.billingError": "支払いポータルへのアクセス中にエラーが発生しました。", + "profile.subscription.cancelSuccess": "サブスクリプションがキャンセルされました。期間終了までアクセスできます。", + "profile.subscription.cancelError": "キャンセル中にエラーが発生しました。", + "profile.subscription.networkError": "ネットワークエラー。", + "profile.usage.title": "今月の使用量", + "profile.usage.resetOn": "リセット日", + "profile.usage.documents": "ドキュメント", + "profile.usage.pages": "ページ", + "profile.usage.extraCredits": "追加クレジット", + "profile.usage.extraCreditsPlural": "追加クレジット", + "profile.usage.quotaReached": "上限に達しました", + "profile.usage.quotaReachedDesc": "引き続きご利用いただくには、上位プランにアップグレードしてください。", + "profile.usage.unlockMore": "有料プランで翻訳数を増やせます。", + "profile.usage.viewPlans": "プランを見る", + "profile.usage.includedInPlan": "プランに含まれています", + "profile.danger.title": "危険区域", + "profile.danger.description": "キャンセルは現在の期間の終了時に反映されます。その日までアクセスは維持されます。", + "profile.danger.confirm": "本当によろしいですか?この操作は取り消せません。", + "profile.danger.confirmCancel": "キャンセルを確認", + "profile.danger.cancelSubscription": "サブスクリプションをキャンセルする", + "profile.danger.keep": "いいえ、維持します", + "profile.prefs.interfaceLang": "インターフェース言語", + "profile.prefs.interfaceLangDesc": "言語はブラウザに基づいて自動検出されます。手動で変更することもできます。", + "profile.prefs.defaultTargetLang": "デフォルトの翻訳先言語", + "profile.prefs.selectLanguage": "言語を選択", + "profile.prefs.defaultTargetLangDesc": "この言語が翻訳時に自動選択されます。", + "profile.prefs.save": "保存", + "profile.prefs.theme": "テーマ", + "profile.prefs.themeDesc": "インターフェースの外観を選択してください", + "profile.prefs.cache": "キャッシュ", + "profile.prefs.cacheDesc": "ローカルキャッシュをクリアすると、一部の表示問題が解決する場合があります。", + "profile.prefs.clearing": "クリア中...", + "profile.prefs.clearCache": "キャッシュをクリア" +} diff --git a/frontend/src/lib/i18n/messages/ja/providerSelector.json b/frontend/src/lib/i18n/messages/ja/providerSelector.json new file mode 100644 index 0000000..9dc8164 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/providerSelector.json @@ -0,0 +1,7 @@ +{ + "providerSelector.noClassic": "利用可能な標準翻訳者はありません。", + "providerSelector.noLlm": "AI モデルが設定されていません。", + "providerSelector.costOne": "料金: 1 ページあたり 1 クレジット", + "providerSelector.costFive": "料金: 1 ページあたり 5 クレジット (プレミアム係数)", + "providerSelector.unlockContextual": "ドキュメント全体の高品質コンテキスト翻訳をアンロック。" +} diff --git a/frontend/src/lib/i18n/messages/ja/providerTheme.json b/frontend/src/lib/i18n/messages/ja/providerTheme.json new file mode 100644 index 0000000..624627e --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/providerTheme.json @@ -0,0 +1,29 @@ +{ + "providerTheme.deepseek.badge": "エッセンシャル", + "providerTheme.deepseek.subBadge": "技術とエコ", + "providerTheme.deepseek.desc": "超高精度で経済的な翻訳。技術文書やコードに最適。", + "providerTheme.openai.badge": "プレミアム", + "providerTheme.openai.subBadge": "高忠実度", + "providerTheme.openai.desc": "AIの世界標準。テキストの一貫性を最大化し、スタイルを厳格に守ります。", + "providerTheme.minimax.badge": "上級", + "providerTheme.minimax.subBadge": "パフォーマンス", + "providerTheme.minimax.desc": "驚異的な実行速度と複雑な構造の優れた理解。", + "providerTheme.openrouter.badge": "エクスプレス", + "providerTheme.openrouter.subBadge": "マルチモデル", + "providerTheme.openrouter.desc": "翻訳に最適化された最高のオープンソースモデルへの統一アクセス。", + "providerTheme.openrouter_premium.badge": "ウルトラ", + "providerTheme.openrouter_premium.subBadge": "最大コンテキスト", + "providerTheme.openrouter_premium.desc": "GPT-4o、Claude Sonnet 4.6 などの最先端モデルによる長文支援。", + "providerTheme.zai.badge": "特化型", + "providerTheme.zai.subBadge": "金融と法律", + "providerTheme.zai.desc": "要求の厳しいビジネス用語 (法務、金融) 向けに微調整されたモデル。", + "providerTheme.default.badge": "モダン", + "providerTheme.default.subBadge": "AI 推論", + "providerTheme.default.desc": "大規模言語モデル (LLM) による、高度な意味分析を伴う翻訳。", + "providerTheme.classic.google.label": "Google 翻訳", + "providerTheme.classic.google.desc": "130 以上の言語に対応する超高速翻訳。一般的なフローにおすすめです。", + "providerTheme.classic.deepl.label": "DeepL Pro", + "providerTheme.classic.deepl.desc": "流暢さと自然な表現で知られる高精度翻訳。", + "providerTheme.classic.google_cloud.label": "Google Cloud API", + "providerTheme.classic.google_cloud.desc": "大量ドキュメント処理に最適化されたプロフェッショナル向けクラウドエンジン。" +} diff --git a/frontend/src/lib/i18n/messages/ja/register.json b/frontend/src/lib/i18n/messages/ja/register.json new file mode 100644 index 0000000..8baca97 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/register.json @@ -0,0 +1,29 @@ +{ + "register.title": "アカウント作成", + "register.subtitle": "無料で翻訳を始めましょう", + "register.error.failed": "登録に失敗しました", + "register.name.label": "名前", + "register.name.placeholder": "お名前", + "register.name.error": "名前は2文字以上で入力してください", + "register.email.label": "メールアドレス", + "register.email.placeholder": "you@example.com", + "register.email.error": "無効なメールアドレス", + "register.password.label": "パスワード", + "register.password.error": "パスワードは8文字以上で、大文字・小文字・数字をそれぞれ1つ以上含めてください", + "register.password.show": "パスワードを表示", + "register.password.hide": "パスワードを非表示", + "register.password.strengthLabel": "強度:", + "register.password.strength.weak": "弱い", + "register.password.strength.medium": "普通", + "register.password.strength.strong": "強い", + "register.confirmPassword.label": "パスワード確認", + "register.confirmPassword.error": "パスワードが一致しません", + "register.confirmPassword.show": "表示", + "register.confirmPassword.hide": "非表示", + "register.submit.creating": "アカウント作成中...", + "register.submit.create": "アカウントを作成", + "register.hasAccount": "すでにアカウントをお持ちですか?", + "register.login": "ログイン", + "register.terms.prefix": "アカウントを作成することで、当社の", + "register.terms.link": "利用規約に同意したことになります" +} diff --git a/frontend/src/lib/i18n/messages/ja/resetPassword.json b/frontend/src/lib/i18n/messages/ja/resetPassword.json new file mode 100644 index 0000000..680714f --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/resetPassword.json @@ -0,0 +1,22 @@ +{ + "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", + "resetPassword.passwordMismatch": "Passwords do not match", + "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", + "resetPassword.error": "An error occurred", + "resetPassword.invalidLink": "Invalid link", + "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", + "resetPassword.requestNewLink": "Request new link", + "resetPassword.successTitle": "Password reset", + "resetPassword.newPasswordTitle": "New password", + "resetPassword.successSubtitle": "You will be redirected to login", + "resetPassword.subtitle": "Set your new password", + "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", + "resetPassword.newPassword": "New password", + "resetPassword.showPassword": "Show password", + "resetPassword.hidePassword": "Hide password", + "resetPassword.confirmPassword": "Confirm password", + "resetPassword.resetting": "Resetting...", + "resetPassword.resetPassword": "Reset password", + "resetPassword.backToLogin": "Back to login", + "resetPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/ja/services.json b/frontend/src/lib/i18n/messages/ja/services.json new file mode 100644 index 0000000..56ec44a --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/services.json @@ -0,0 +1,14 @@ +{ + "services.title": "翻訳プロバイダー", + "services.subtitle": "プロバイダーは管理者によって設定されます。現在アカウントで利用可能なプロバイダーを確認できます。", + "services.loading": "プロバイダーを読み込み中...", + "services.noProviders": "現在設定されているプロバイダーはありません。管理者にお問い合わせください。", + "services.classic": "クラシック翻訳", + "services.llmPro": "LLM · コンテキスト認識 (Pro)", + "services.available": "利用可能", + "services.model": "モデル", + "services.adminOnly.title": "プロバイダーの設定は管理者のみ", + "services.adminOnly.desc": "APIキー、モデルの選択、プロバイダーの有効化は管理者が管理パネルで管理します。APIキーを入力する必要はありません。", + "services.fallback.google.label": "Google 翻訳", + "services.fallback.google.desc": "高速翻訳、130 以上の言語" +} diff --git a/frontend/src/lib/i18n/messages/ja/settings.json b/frontend/src/lib/i18n/messages/ja/settings.json new file mode 100644 index 0000000..ac3a109 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/settings.json @@ -0,0 +1,20 @@ +{ + "settings.title": "設定", + "settings.subtitle": "アプリケーションの全般設定", + "settings.formats.title": "対応フォーマット", + "settings.formats.subtitle": "翻訳可能なドキュメントの種類", + "settings.formats.formulas": "数式", + "settings.formats.styles": "スタイル", + "settings.formats.images": "画像", + "settings.formats.headers": "ヘッダー", + "settings.formats.tables": "テーブル", + "settings.formats.slides": "スライド", + "settings.formats.notes": "ノート", + "settings.cache.title": "キャッシュ", + "settings.cache.desc": "ローカルキャッシュをクリアすると、一部の表示問題が解決する場合があります。", + "settings.cache.clearing": "クリア中...", + "settings.cache.clear": "キャッシュをクリア", + "settings.formats.excel.name": "Excel", + "settings.formats.word.name": "Word", + "settings.formats.powerpoint.name": "PowerPoint" +} diff --git a/frontend/src/lib/i18n/messages/ja/translate.json b/frontend/src/lib/i18n/messages/ja/translate.json new file mode 100644 index 0000000..b647efe --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/translate.json @@ -0,0 +1,92 @@ +{ + "translate.mode.label": "Mode de traduction", + "translate.mode.classic": "Classique", + "translate.mode.classicDesc": "Rapide", + "translate.mode.proLlm": "Pro LLM", + "translate.mode.proLlmDesc": "Contextuel", + "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", + "translate.mode.upgradeLink": "Passer à Pro", + "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", + "translate.glossary.title": "用語集", + "translate.glossary.select": "用語集を選択", + "translate.glossary.none": "なし", + "translate.glossary.terms": "件", + "translate.glossary.proOnly": "Proにアップグレードして用語集を使用", + "translate.glossary.myGlossaries": "マイ用語集", + "translate.glossary.fromTemplate": "テンプレートから作成", + "translate.glossary.noGlossaryForPair": "用語集なし", + "translate.glossary.noGlossaries": "用語集なし", + "translate.glossary.loading": "読み込み中...", + "translate.glossary.classicMode": "用語集なしのニュートラルエンジン(AIのみ)", + "translate.glossary.selectPlaceholder": "用語集を選択...", + "translate.glossary.multilingual": "多言語", + "translate.glossary.noGlossaryAvailable": "利用可能な用語集なし", + "translate.glossary.filterByLang": "言語で絞り込み", + "translate.glossary.active": "有効", + "translate.glossary.inactive": "無効", + "translate.glossary.availableTemplates": "利用可能なテンプレート", + "translate.glossary.importing": "インポート中...", + "translate.glossary.imported": "(インポート済み)", + "translate.glossary.noGlossaryForSource": "ソース言語の用語集・テンプレートなし", + "translate.glossary.createGlossary": "用語集を作成", + "translate.glossary.showAll": "すべての用語集を表示", + "translate.glossary.activePreview": "アクティブな一致のプレビュー:", + "translate.glossary.total": "合計", + "translate.glossary.moreTerms": "その他の用語", + "translate.glossary.noTerms": "この用語集には用語がありません。", + "translate.glossary.sourceTerm": "ソース用語", + "translate.glossary.translation": "翻訳", + "translate.glossary.addTerm": "用語を追加", + "translate.glossary.disabledMode": "用語集が適用されていないニュートラルエンジン", + "translate.glossary.addTermError": "用語の追加エラー", + "translate.glossary.networkError": "ネットワークエラー", + "translate.glossary.importFailed": "インポートに失敗しました ({status})", + "translate.glossary.helpText": "用語集は正確な用語翻訳を強制します。ソース言語がドキュメントの元の言語と一致する用語集を選択してください。", + "translate.glossary.sourceWarning": "警告:この用語集はソース言語を使用しています", + "translate.glossary.sourceWarningBut": "ただし、ドキュメントは次の言語に設定されています", + "translate.glossary.targetWarning": "ターゲットの不一致:この用語集は次の言語への翻訳用です", + "translate.glossary.targetWarningBut": "ただし、ドキュメントのターゲットは", + "translate.glossary.targetWarningEnd": "用語が関連しない場合があります。", + "translate.header.processing": "処理中", + "translate.header.aiActive": "AI 分析アクティブ", + "translate.header.aiActiveDesc": "レイアウトはコンテキストエンジンによって保持されています。", + "translate.header.completed": "完了", + "translate.header.completedTitle": "翻訳完了", + "translate.header.proSpace": "Pro スペース", + "translate.header.translateDoc": "ドキュメントを翻訳", + "translate.header.translateDocDesc": "超高忠実度の翻訳エンジンで元のレイアウトを保持します。", + "translate.upload.nativeFormat": "ネイティブ形式", + "translate.fileType.word": "Word (.docx)", + "translate.fileType.excel": "Excel (.xlsx)", + "translate.fileType.slides": "スライド (.pptx)", + "translate.fileType.pdf": "PDF (.pdf)", + "translate.startTranslation": "翻訳を開始", + "translate.submit": "送信中…", + "translate.chooseTargetLang": "翻訳先の言語を選択してください", + "translate.pleaseLoadFile": "まずファイルをアップロードしてください", + "translate.contextEngineActive": "コンテキストエンジン作動中", + "translate.phase1": "フェーズ 1: 初期化", + "translate.phase2": "フェーズ 2: コンテキスト再構築", + "translate.stat.segments": "セグメント", + "translate.stat.precision": "精度", + "translate.stat.speedLabel": "速度", + "translate.stat.turbo": "ターボ", + "translate.stat.time": "時間", + "translate.complete.masterQuality": "✓ マスター品質", + "translate.download": "ダウンロード", + "translate.newTranslation": "+ 新しい翻訳", + "translate.failedTitle": "翻訳エラー", + "translate.retry": "再試行", + "translate.uploadAnother": "別のファイルをアップロード", + "translate.monitor": "AI モニター", + "translate.summary": "サマリー", + "translate.cancelProcess": "⟳ プロセスをキャンセル", + "translate.layoutIntegrity": "レイアウト整合性", + "translate.secureHundred": "100% 安全", + "translate.okHundred": "100% OK", + "translate.preserveLayout": "レイアウトを保持", + "translate.preserveLayoutDesc": "レイアウトを保持", + "translate.textOnly": "テキストのみ", + "translate.textOnlyDesc": "テキストのみの高速翻訳", + "translate.unavailableStandard": "標準モードでは利用できません (AI のみ)" +} diff --git a/frontend/src/lib/i18n/messages/ja/translateComplete.json b/frontend/src/lib/i18n/messages/ja/translateComplete.json new file mode 100644 index 0000000..9d1dae1 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ja/translateComplete.json @@ -0,0 +1,6 @@ +{ + "translateComplete.highQuality": "高品質", + "translateComplete.segments": "セグメント", + "translateComplete.characters": "文字", + "translateComplete.confidence": "信頼度" +} diff --git a/frontend/src/lib/i18n/messages/ko/admin.json b/frontend/src/lib/i18n/messages/ko/admin.json new file mode 100644 index 0000000..e88b24d --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/admin.json @@ -0,0 +1,48 @@ +{ + "admin.login.title": "관리", + "admin.login.required": "로그인 필요", + "admin.login.password": "관리자 비밀번호", + "admin.login.connecting": "연결 중...", + "admin.login.access": "관리 패널 접속", + "admin.login.restricted": "관리자 전용", + "admin.layout.checking": "인증 확인 중...", + "admin.dashboard.title": "관리 대시보드", + "admin.dashboard.subtitle": "관리자 제어판", + "admin.dashboard.refresh": "새로고침", + "admin.dashboard.refreshTooltip": "대시보드 데이터 새로고침", + "admin.dashboard.config": "시스템 구성", + "admin.dashboard.maxFileSize": "최대 파일 크기:", + "admin.dashboard.translationService": "번역 서비스:", + "admin.dashboard.formats": "형식:", + "admin.nav.dashboard": "Dashboard", + "admin.nav.users": "사용자", + "admin.nav.pricing": "요금 & Stripe", + "admin.nav.providers": "제공업체", + "admin.nav.system": "시스템", + "admin.nav.logs": "로그", + "admin.users.title": "사용자 관리", + "admin.users.subtitle": "사용자 계정 보기 및 관리", + "admin.users.planUpdated": "플랜이 업데이트되었습니다", + "admin.users.planChanged": "플랜이 \\\"{plan}\\\"(으)로 성공적으로 변경되었습니다.", + "admin.users.unknownError": "알 수 없는 오류", + "admin.users.error": "오류", + "admin.users.planUpdateError": "플랜을 업데이트할 수 없습니다: {message}", + "admin.users.noKeys": "키 없음", + "admin.users.noKeysDesc": "이 사용자는 활성 API 키가 없습니다.", + "admin.users.keysRevoked": "키가 취소되었습니다", + "admin.users.keysRevokedDesc": "{count}개의 API 키가 성공적으로 취소되었습니다.", + "admin.users.revokeError": "키를 취소할 수 없습니다: {message}", + "admin.users.retry": "재시도", + "admin.system.title": "시스템", + "admin.system.subtitle": "시스템 상태 모니터링 및 리소스 관리", + "admin.system.quotas": "번역 할당량", + "admin.system.resetQuotas": "월간 할당량 초기화", + "admin.system.resetting": "초기화 중...", + "admin.system.reset": "초기화", + "admin.system.allOperational": "모든 시스템 정상 가동 중", + "admin.system.issuesDetected": "시스템 문제가 감지되었습니다", + "admin.system.waitingData": "데이터 대기 중...", + "admin.system.purging": "삭제 중...", + "admin.system.clean": "정리", + "admin.system.purge": "삭제" +} diff --git a/frontend/src/lib/i18n/messages/ko/apiKeys.json b/frontend/src/lib/i18n/messages/ko/apiKeys.json new file mode 100644 index 0000000..1ccd6d9 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/apiKeys.json @@ -0,0 +1,72 @@ +{ + "apiKeys.webhook.title": "Intégration Webhook", + "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", + "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", + "apiKeys.webhook.codeParam": "webhook_url", + "apiKeys.title": "API 키", + "apiKeys.subtitle": "번역 API에 프로그래밍 방식으로 접근하기 위한 API 키를 관리합니다.", + "apiKeys.loading": "로딩 중...", + "apiKeys.sectionTitle": "API & 자동화", + "apiKeys.sectionDesc": "자동화 워크플로우를 위한 API 키 생성 및 관리", + "apiKeys.keysUsed": "{total} / {max} 키 사용", + "apiKeys.maxReached": "최대 키 수에 도달했습니다. 새 키를 생성하려면 기존 키를 취소하세요.", + "apiKeys.canGenerate": "{count}개의 키를 더 생성할 수 있습니다", + "apiKeys.canGeneratePlural": "{count}개의 키를 더 생성할 수 있습니다", + "apiKeys.generateNew": "새 키 생성", + "apiKeys.keyRevoked": "키가 취소되었습니다", + "apiKeys.keyRevokedDesc": "API 키가 성공적으로 취소되었습니다.", + "apiKeys.keyNotFound": "키를 찾을 수 없음", + "apiKeys.keyNotFoundDesc": "API 키가 더 이상 존재하지 않습니다. 이미 취소되었을 수 있습니다.", + "apiKeys.error": "오류", + "apiKeys.revokeError": "API 키 취소에 실패했습니다. 다시 시도해 주세요.", + "apiKeys.limitReached": "한도 도달", + "apiKeys.limitReachedDesc": "API 키는 최대 10개까지입니다. 새 키를 생성하려면 기존 키를 취소하세요.", + "apiKeys.proRequired": "Pro 기능 필요", + "apiKeys.proRequiredDesc": "API 키는 Pro 기능입니다. 계정을 업그레이드해 주세요.", + "apiKeys.generateError": "API 키 생성에 실패했습니다. 다시 시도해 주세요.", + "apiKeys.upgrade.title": "API 키", + "apiKeys.upgrade.subtitle": "API 액세스로 번역 자동화", + "apiKeys.upgrade.feat1": "무제한 API 키 생성", + "apiKeys.upgrade.feat2": "문서 번역 자동화", + "apiKeys.upgrade.feat3": "웹훅 알림", + "apiKeys.upgrade.feat4": "LLM 번역 모드", + "apiKeys.upgrade.proFeature": "API 키는 {pro} 기능입니다. 업그레이드하여 API 자동화를 잠금 해제하세요.", + "apiKeys.upgrade.pro": "Pro", + "apiKeys.upgrade.cta": "Pro로 업그레이드", + "apiKeys.dialog.maxTitle": "최대 키 수 도달", + "apiKeys.dialog.maxDesc": "API 키는 최대 10개까지입니다. 새 키를 생성하기 전에 기존 키를 취소해 주세요.", + "apiKeys.dialog.close": "닫기", + "apiKeys.dialog.generated": "API 키가 생성되었습니다!", + "apiKeys.dialog.generatedDesc": "새 API 키가 생성되었습니다. 지금 복사하세요 - 다시 표시되지 않습니다.", + "apiKeys.dialog.important": "중요:", + "apiKeys.dialog.importantDesc": "이 키가 표시되는 것은 이번뿐입니다. 안전하게 보관하세요.", + "apiKeys.dialog.apiKey": "API 키", + "apiKeys.dialog.name": "이름:", + "apiKeys.dialog.done": "완료", + "apiKeys.dialog.copied": "키를 복사했습니다", + "apiKeys.dialog.generateTitle": "새 API 키 생성", + "apiKeys.dialog.generateDesc": "번역 API에 프로그래밍 방식으로 접근하기 위한 새 API 키를 생성합니다.", + "apiKeys.dialog.keyName": "키 이름 (선택사항)", + "apiKeys.dialog.keyNamePlaceholder": "예: 프로덕션, 스테이징", + "apiKeys.dialog.keyNameHint": "나중에 이 키를 식별할 수 있는 설명적인 이름.", + "apiKeys.dialog.nameTooLong": "이름은 {max}자 이하여야 합니다", + "apiKeys.dialog.nameInvalid": "이름은 문자, 숫자, 공백, 하이픈, 밑줄만 포함할 수 있습니다", + "apiKeys.dialog.cancel": "취소", + "apiKeys.dialog.generating": "생성 중...", + "apiKeys.dialog.generate": "키 생성", + "apiKeys.table.name": "이름", + "apiKeys.table.prefix": "접두사", + "apiKeys.table.created": "생성일", + "apiKeys.table.lastUsed": "마지막 사용", + "apiKeys.table.never": "사용 안 함", + "apiKeys.table.actions": "작업", + "apiKeys.table.revoke": "취소", + "apiKeys.table.copyPrefix": "키 접두사 복사", + "apiKeys.table.revokeKey": "키 취소", + "apiKeys.revokeDialog.title": "API 키 취소", + "apiKeys.revokeDialog.desc": "키 \\\"{name}\\\"을(를) 취소하시겠습니까? 이 작업은 되돌릴 수 없습니다.", + "apiKeys.revokeDialog.confirm": "예, 취소합니다", + "apiKeys.revokeDialog.cancel": "취소", + "apiKeys.noKeysGenerated": "생성된 키 없음", + "apiKeys.copied": "복사됨!" +} diff --git a/frontend/src/lib/i18n/messages/ko/auth.json b/frontend/src/lib/i18n/messages/ko/auth.json new file mode 100644 index 0000000..b300370 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/auth.json @@ -0,0 +1,3 @@ +{ + "auth.brandName": "Wordly" +} diff --git a/frontend/src/lib/i18n/messages/ko/checkout.json b/frontend/src/lib/i18n/messages/ko/checkout.json new file mode 100644 index 0000000..d7f417a --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/checkout.json @@ -0,0 +1,12 @@ +{ + "checkout.activating": "활성화 중…", + "checkout.activatingDesc": "구독을 업데이트 중입니다. 잠시 기다려 주세요.", + "checkout.paymentConfirmed": "결제 확인됨!", + "checkout.subscriptionActivated": "구독이 활성화되었습니다!", + "checkout.planActivated": "{plan} 요금제가 활성화되었습니다!", + "checkout.redirectingToProfile": "프로필로 리디렉션 중…", + "checkout.paymentReceived": "결제 받음", + "checkout.redirecting": "리디렉션 중…", + "checkout.syncError": "동기화 오류", + "checkout.networkError": "네트워크 오류. 결제가 확인되었습니다 — 프로필을 새로 고치세요." +} diff --git a/frontend/src/lib/i18n/messages/ko/common.json b/frontend/src/lib/i18n/messages/ko/common.json new file mode 100644 index 0000000..eadad79 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/common.json @@ -0,0 +1,4 @@ +{ + "common.loading": "로딩 중...", + "common.backToHome": "홈으로 돌아가기" +} diff --git a/frontend/src/lib/i18n/messages/ko/context.json b/frontend/src/lib/i18n/messages/ko/context.json new file mode 100644 index 0000000..558f67a --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/context.json @@ -0,0 +1,25 @@ +{ + "context.proTitle": "Pro 기능", + "context.proDesc": "컨텍스트 및 전문 용어집은 Pro, Business, Enterprise 플랜에서 사용할 수 있습니다. 도메인별 지침과 어휘를 통해 더 정확한 번역을 제공합니다.", + "context.viewPlans": "플랜 보기", + "context.title": "컨텍스트 & 용어집", + "context.subtitle": "도메인별 지침과 어휘로 번역 품질을 향상시킵니다.", + "context.presets.title": "전문 용어집", + "context.presets.desc": "지침과 전문 용어가 포함된 완전한 용어집을 불러옵니다", + "context.instructions.title": "컨텍스트 지침", + "context.instructions.desc": "번역 중 AI가 따를 지침", + "context.instructions.placeholder": "예: HVAC 기술 문서를 번역합니다. 정확한 공학 용어를 사용하세요...", + "context.glossary.title": "기술 용어집", + "context.glossary.desc": "형식: source=target (한 줄에 하나). 프리셋으로 불러온 용어집은 편집 가능합니다.", + "context.glossary.terms": "용어집의 용어 수", + "context.clearAll": "모두 지우기", + "context.saving": "저장 중...", + "context.save": "저장", + "context.presets.createGlossary": "용어집 만들기", + "context.presets.created": "용어집 생성됨", + "context.presets.createdDesc": "용어집 \\\"{name}\\\"이(가) {count}개의 용어로 생성되었습니다.", + "context.presets.hint": "프리셋을 클릭하여 도메인별 용어가 포함된 용어집을 만드세요. 용어집 섹션에서 관리할 수 있습니다.", + "context.glossary.manage": "용어집 관리", + "context.saved": "저장됨", + "context.savedDesc": "컨텍스트 지침이 저장되었습니다." +} diff --git a/frontend/src/lib/i18n/messages/ko/cookieConsent.json b/frontend/src/lib/i18n/messages/ko/cookieConsent.json new file mode 100644 index 0000000..16b8d49 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/cookieConsent.json @@ -0,0 +1,7 @@ +{ + "cookieConsent.title": "Wordly 쿠키", + "cookieConsent.description": "앱 작동에 필요한 필수 쿠키를 사용합니다(세션, 보안, 언어). 허락하시면 트래픽 측정 및 제품 개선을 위한 선택적 쿠키도 사용합니다.", + "cookieConsent.acceptAll": "모두 허용", + "cookieConsent.essentialOnly": "필수만", + "cookieConsent.learnMore": "자세히 보기" +} diff --git a/frontend/src/lib/i18n/messages/ko/dashboard.json b/frontend/src/lib/i18n/messages/ko/dashboard.json new file mode 100644 index 0000000..784f832 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/dashboard.json @@ -0,0 +1,111 @@ +{ + "dashboard.nav.translate": "번역", + "dashboard.nav.profile": "내 프로필", + "dashboard.nav.settings": "설정", + "dashboard.nav.context": "컨텍스트", + "dashboard.nav.services": "서비스", + "dashboard.nav.apiKeys": "API 키", + "dashboard.nav.glossaries": "용어집", + "dashboard.header.title": "대시보드", + "dashboard.header.subtitle": "번역 관리", + "dashboard.header.toggleMenu": "메뉴", + "dashboard.header.profileTitle": "내 프로필", + "dashboard.sidebar.theme": "테마", + "dashboard.sidebar.signOut": "로그아웃", + "dashboard.sidebar.backHome": "홈으로 돌아가기", + "dashboard.sidebar.upgradeToPro": "Pro로 업그레이드 →", + "dashboard.translate.pageTitle": "문서 번역", + "dashboard.translate.pageSubtitle": "파일을 가져오고 대상 언어를 선택하세요", + "dashboard.translate.errorNotificationTitle": "오류", + "dashboard.translate.dropzone.uploadAria": "파일 드롭 영역", + "dashboard.translate.dropzone.title": "여기에 파일을 드래그 앤 드롭하세요", + "dashboard.translate.dropzone.subtitle": "또는 클릭하여 선택 (DOCX, XLSX, PPTX, PDF)", + "dashboard.translate.dropzone.replaceFile": "파일 교체", + "dashboard.translate.language.source": "원본 언어", + "dashboard.translate.language.target": "대상 언어", + "dashboard.translate.language.loading": "언어 로딩 중…", + "dashboard.translate.language.autoDetect": "자동 감지", + "dashboard.translate.language.selectPlaceholder": "선택…", + "dashboard.translate.language.loadErrorPrefix": "언어 로딩 실패", + "dashboard.translate.provider.loading": "제공업체 로딩 중…", + "dashboard.translate.provider.noneConfigured": "구성된 제공업체 없음", + "dashboard.translate.provider.modelTitle": "모델", + "dashboard.translate.provider.sectionTitle": "제공업체", + "dashboard.translate.provider.llmDivider": "AI · 문맥 인식", + "dashboard.translate.provider.llmDividerPro": "AI · 문맥 인식 (Pro)", + "dashboard.translate.provider.upgrade": "Pro로 업그레이드", + "dashboard.translate.provider.upgradeSuffix": "AI 번역 잠금 해제", + "dashboard.translate.trust.zeroRetention": "데이터 미보관", + "dashboard.translate.trust.deletedAfter": "처리 후 파일 삭제", + "dashboard.translate.actions.uploading": "업로드 중…", + "dashboard.translate.actions.translate": "번역", + "dashboard.translate.actions.filePrefix": "파일: ", + "dashboard.translate.actions.cancel": "취소", + "dashboard.translate.actions.tryAgain": "다시 시도", + "dashboard.translate.steps.uploading": "파일 업로드 중…", + "dashboard.translate.steps.starting": "번역 시작 중…", + "dashboard.translate.complete.title": "번역 완료!", + "dashboard.translate.complete.descNamed": "파일 {name}의 번역이 성공적으로 완료되었습니다.", + "dashboard.translate.complete.descGeneric": "파일의 번역이 성공적으로 완료되었습니다.", + "dashboard.translate.complete.downloading": "다운로드 중…", + "dashboard.translate.complete.download": "다운로드", + "dashboard.translate.complete.newTranslation": "새 번역", + "dashboard.translate.complete.toastOkTitle": "성공", + "dashboard.translate.complete.toastOkDesc": "{name} 다운로드가 완료되었습니다.", + "dashboard.translate.complete.toastFailTitle": "실패", + "dashboard.translate.complete.toastFailDesc": "번역에 실패했습니다. 다시 시도해 주세요.", + "dashboard.translate.sourceDocument": "원본 문서", + "dashboard.translate.configuration": "설정", + "dashboard.translate.translating": "번역 진행 중", + "dashboard.translate.liveMonitor": "실시간 모니터", + "dashboard.translate.summary": "요약", + "dashboard.translate.engine": "엔진", + "dashboard.translate.confidence": "신뢰도", + "dashboard.translate.cancel": "취소", + "dashboard.translate.segments": "세그먼트", + "dashboard.translate.characters": "문자", + "dashboard.translate.elapsed": "경과", + "dashboard.translate.segPerMin": "세그/분", + "dashboard.translate.highQuality": "고품질", + "dashboard.translate.quality": "품질", + "dashboard.translate.completed": "번역 완료", + "dashboard.translate.replace": "교체", + "dashboard.translate.pdfMode.title": "PDF 번역 모드", + "dashboard.translate.pdfMode.preserveLayout": "레이아웃 유지", + "dashboard.translate.pdfMode.textOnly": "텍스트만", + "dashboard.translate.pdfMode.preserveLayoutDesc": "이미지, 표 및 서식을 유지합니다. 간단한 PDF에 적합.", + "dashboard.translate.pdfMode.textOnlyDesc": "모든 텍스트를 완벽하게 번역합니다. 깔끔한 출력, 레이아웃 문제 없음.", + "dashboard.translate.pipeline.upload": "업로드", + "dashboard.translate.pipeline.analyze": "분석", + "dashboard.translate.pipeline.translate": "번역", + "dashboard.translate.pipeline.rebuild": "재구성", + "dashboard.translate.pipeline.finalize": "완료", + "dashboard.translate.progress.processingFallback": "처리 중…", + "dashboard.translate.progress.connectionLost": "연결이 끊어졌습니다. 재시도 중…", + "dashboard.translate.progress.failedTitle": "번역 실패", + "dashboard.translate.error.unexpected": "예기치 않은 오류가 발생했습니다. 다시 시도해 주세요.", + "dashboard.translate.error.noResult": "번역 결과가 없습니다. 문서에 텍스트가 포함되어 있는지 확인하고 다시 시도하거나 다른 엔진을 선택하세요.", + "dashboard.translate.error.apiKey": "API 키가 유효하지 않거나 없습니다. 관리자에게 문의하여 API 키를 설정하세요.", + "dashboard.translate.error.quota": "사용 한도에 도달했습니다. 몇 분 후에 다시 시도하거나 다른 엔진을 선택하세요.", + "dashboard.translate.error.timeout": "번역 서비스 연결 시간이 초과되었습니다. 네트워크를 확인하고 다시 시도하세요.", + "dashboard.translate.error.sessionExpired": "세션이 만료되었습니다. 다시 시도를 클릭하여 번역을 재시작하세요.", + "dashboard.translate.error.empty": "문서가 비어 있거나 번역 가능한 텍스트가 없습니다 (스캔 PDF 이미지?).", + "dashboard.translate.error.unsupported": "지원되지 않는 파일 형식이거나 손상된 파일입니다.", + "dashboard.translate.error.connection": "연결이 끊겼습니다. 네트워크를 확인하고 다시 시도하세요.", + "dashboard.translate.error.generic": "번역 실패: {detail}", + "dashboard.translate.error.title": "번역 실패", + "dashboard.translate.retry": "번역 다시 시도", + "dashboard.translate.newFile": "새 파일", + "dashboard.translate.modeAI": "AI 모드", + "dashboard.translate.modeClassic": "클래식 모드", + "dashboard.translate.glossaryLLMHint": "AI 모드에서 용어집 사용 가능", + "dashboard.translate.submitting": "제출 중...", + "dashboard.translate.submit": "번역 시작", + "dashboard.translate.noFile": "먼저 파일을 업로드하세요", + "dashboard.translate.noTargetLang": "대상 언어를 선택하세요", + "dashboard.topbar.interfaceLabel": "번역 인터페이스", + "dashboard.topbar.premiumAccess": "프리미엄 액세스", + "dashboard.checkoutSyncError": "결제 동기화 오류.", + "dashboard.networkRefresh": "네트워크 오류. 페이지를 새로 고치세요.", + "dashboard.continueToTranslate": "번역으로 계속" +} diff --git a/frontend/src/lib/i18n/messages/ko/fileUploader.json b/frontend/src/lib/i18n/messages/ko/fileUploader.json new file mode 100644 index 0000000..ed3df24 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/fileUploader.json @@ -0,0 +1,31 @@ +{ + "fileUploader.uploadDocument": "문서 업로드", + "fileUploader.uploadDesc": "파일을 끌어다 놓거나 클릭하여 선택 (Excel, Word, PowerPoint)", + "fileUploader.dropHere": "파일을 여기에 놓으세요…", + "fileUploader.dragAndDrop": "여기에 문서를 끌어다 놓으세요", + "fileUploader.orClickBrowse": "또는 클릭하여 찾아보기", + "fileUploader.preview": "미리보기", + "fileUploader.translationOptions": "번역 옵션", + "fileUploader.configureSettings": "번역 설정 구성", + "fileUploader.targetLanguage": "대상 언어", + "fileUploader.selectLanguage": "언어 선택", + "fileUploader.translationProvider": "번역 공급자", + "fileUploader.selectProvider": "공급자 선택", + "fileUploader.advancedOptions": "고급 옵션", + "fileUploader.translateImages": "이미지 번역", + "fileUploader.translating": "번역 중…", + "fileUploader.translateDocument": "문서 번역", + "fileUploader.processing": "처리 중…", + "fileUploader.translationError": "번역 오류", + "fileUploader.translationComplete": "번역 완료!", + "fileUploader.translationCompleteDesc": "서식을 모두 유지한 채 문서가 성공적으로 번역되었습니다.", + "fileUploader.download": "번역된 문서 다운로드", + "fileUploader.webgpuUnsupported": "이 브라우저는 WebGPU를 지원하지 않습니다. Chrome 113+ 또는 Edge 113+를 사용하세요.", + "fileUploader.webllmNotLoaded": "WebLLM 모델이 로드되지 않았습니다. 설정 > 번역 서비스에서 모델을 먼저 로드하세요.", + "fileUploader.extracting": "문서에서 텍스트 추출 중…", + "fileUploader.noTranslatable": "문서에서 번역 가능한 텍스트를 찾을 수 없음", + "fileUploader.foundTexts": "번역할 텍스트 {count}개 발견", + "fileUploader.translatingItem": "번역 중 {current}/{total}: \\\"{preview}\\\"", + "fileUploader.reconstructing": "문서 재구성 중…", + "fileUploader.translatingLocally": "WebLLM으로 로컬 번역 중…" +} diff --git a/frontend/src/lib/i18n/messages/ko/forgotPassword.json b/frontend/src/lib/i18n/messages/ko/forgotPassword.json new file mode 100644 index 0000000..0ac67c8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/forgotPassword.json @@ -0,0 +1,14 @@ +{ + "forgotPassword.enterEmail": "Please enter your email address", + "forgotPassword.error": "An error occurred", + "forgotPassword.title": "Forgot Password", + "forgotPassword.checkEmail": "Check your inbox", + "forgotPassword.subtitle": "Enter your email to receive a reset link", + "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", + "forgotPassword.emailLabel": "Email address", + "forgotPassword.emailPlaceholder": "you@example.com", + "forgotPassword.sending": "Sending...", + "forgotPassword.sendLink": "Send reset link", + "forgotPassword.backToLogin": "Back to login", + "forgotPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/ko/glossaries.json b/frontend/src/lib/i18n/messages/ko/glossaries.json new file mode 100644 index 0000000..9127aac --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/glossaries.json @@ -0,0 +1,189 @@ +{ + "glossaries.yourGlossaries": "내 용어집", + "glossaries.title": "용어집 및 컨텍스트", + "glossaries.description": "용어집과 컨텍스트 지침을 관리하여 더 정확한 번역을하세요.", + "glossaries.createNew": "새로 만들기", + "glossaries.empty": "용어집이 없습니다", + "glossaries.emptyDesc": "첫 번째 용어집을 만들거나 위에서 전문 프리셋을 로드하세요", + "glossaries.defineTerms": "용어", + "glossaries.aboutTitle": "용어집 정보", + "glossaries.aboutDesc": "용어집을 사용하면 특정 용어에 대한 정확한 번역을 정의할 수 있습니다. 번역 시 용어집 용어가 사용되어 일관되고 정확한 번역이 보장됩니다.", + "glossaries.aboutFormat": "각 용어에는 원본 단어와 여러 언어의 번역이 있습니다. 번역 페이지에서 용어집을 선택하여 적용하세요.", + "glossaries.toast.created": "용어집 생성됨", + "glossaries.toast.createdDesc": "용어집 \\\"{name}\\\"이(가) 생성되었습니다.", + "glossaries.toast.imported": "용어집 가져오기 완료", + "glossaries.toast.importedDesc": "용어집 \\\"{name}\\\"을(를) 가져왔습니다.", + "glossaries.toast.updated": "용어집 업데이트됨", + "glossaries.toast.updatedDesc": "용어집 \\\"{name}\\\"이(가) 업데이트되었습니다.", + "glossaries.toast.deleted": "용어집 삭제됨", + "glossaries.toast.deletedDesc": "용어집이 삭제되었습니다.", + "glossaries.toast.error": "오류", + "glossaries.toast.errorCreate": "용어집 생성 실패", + "glossaries.toast.errorImport": "용어집 가져오기 실패", + "glossaries.toast.errorUpdate": "용어집 업데이트 실패", + "glossaries.toast.errorDelete": "용어집 삭제 실패", + "glossaries.dialog.title": "새 용어집", + "glossaries.dialog.description": "번역을 위한 용어집을 만드세요", + "glossaries.dialog.nameLabel": "이름", + "glossaries.dialog.namePlaceholder": "내 용어집", + "glossaries.dialog.tabTemplates": "템플릿", + "glossaries.dialog.tabFile": "파일", + "glossaries.dialog.tabManual": "수동", + "glossaries.dialog.cancel": "취소", + "glossaries.dialog.creating": "생성 중…", + "glossaries.dialog.importing": "가져오는 중…", + "glossaries.dialog.importBtn": "가져오기", + "glossaries.dialog.selectPrompt": "선택", + "glossaries.dialog.createBtn": "생성", + "glossaries.dialog.createEmpty": "빈 용어집 생성", + "glossaries.dialog.terms": "개 용어", + "glossaries.dialog.templatesDesc": "미리 정의된 템플릿을 선택하세요", + "glossaries.dialog.templatesEmpty": "사용 가능한 템플릿이 없습니다", + "glossaries.dialog.dropTitle": "CSV 파일을 여기로 드래그하세요", + "glossaries.dialog.dropOr": "또는", + "glossaries.dialog.dropFormats": "CSV, TSV, TXT", + "glossaries.termEditor.addTerm": "용어 추가", + "glossaries.termEditor.maxReached": "용어집당 최대 {max}개 용어에 도달했습니다.", + "glossaries.dialog.formatTitle": "형식", + "glossaries.dialog.formatDesc": "원본,대상 (한 줄에 하나씩)", + "glossaries.dialog.formatNote": "헤더가 감지되면 첫 줄은 건너뜁니다", + "glossaries.dialog.errorFormat": "지원되지 않는 형식", + "glossaries.dialog.errorSize": "파일이 너무 큽니다", + "glossaries.dialog.errorEmpty": "빈 파일", + "glossaries.dialog.errorRead": "읽기 오류", + "glossaries.dialog.parsing": "구문 분석 중…", + "glossaries.dialog.termsImported": "개 용어 가져옴", + "glossaries.dialog.changeFile": "파일 변경", + "glossaries.dialog.retry": "다시 시도", + "glossaries.edit.title": "Modifier le glossaire", + "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", + "glossaries.edit.nameLabel": "Nom du glossaire", + "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", + "glossaries.edit.sourceLang": "Langue source", + "glossaries.edit.targetLang": "Langue cible", + "glossaries.edit.termsLabel": "Termes ({count} valides)", + "glossaries.edit.exportCsv": "Exporter CSV", + "glossaries.edit.importCsv": "Importer CSV", + "glossaries.edit.cancel": "Annuler", + "glossaries.edit.saving": "Enregistrement...", + "glossaries.edit.saveChanges": "Enregistrer les modifications", + "glossaries.edit.importFailedTitle": "Échec de l'importation", + "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", + "glossaries.edit.importSuccessTitle": "Importation réussie", + "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", + "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", + "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", + "glossaries.delete.title": "Supprimer le glossaire", + "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", + "glossaries.delete.warning": "Cette action est irréversible", + "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", + "glossaries.delete.cancel": "Annuler", + "glossaries.delete.deleting": "Suppression...", + "glossaries.delete.deleteBtn": "Supprimer", + "glossaries.upgrade.title": "Glossaires", + "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", + "glossaries.upgrade.feature1": "Créez plusieurs glossaires", + "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", + "glossaries.upgrade.feature3": "Importez/exportez via CSV", + "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", + "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", + "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", + "glossaries.upgrade.proLabel": "Pro", + "glossaries.upgrade.upgradeBtn": "Passer à Pro", + "glossaries.loading": "Chargement...", + "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", + "glossaries.howItWorks.step1Title": "Configurez ici", + "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", + "glossaries.howItWorks.step2Title": "Activez dans Traduire", + "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", + "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", + "glossaries.howItWorks.goToTranslate": "Aller à Traduire", + "glossaries.status.unsaved": "Non enregistré", + "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", + "glossaries.status.inactive": "Inactif", + "glossaries.instructions.whatForBold": "À quoi ça sert ?", + "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", + "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", + "glossaries.instructions.charCount": "{count} caractères", + "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", + "glossaries.instructions.clearAll": "Tout effacer", + "glossaries.instructions.saving": "Enregistrement…", + "glossaries.instructions.saved": "Enregistré", + "glossaries.presets.whatForBold": "À quoi ça sert ?", + "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", + "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", + "glossaries.presets.creating": "Création…", + "glossaries.presets.alreadyImported": "Déjà importé", + "glossaries.presets.it.title": "IT / Logiciel", + "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", + "glossaries.presets.legal.title": "Juridique / Contrats", + "glossaries.presets.legal.desc": "Droit des affaires, contentieux", + "glossaries.presets.medical.title": "Médical / Santé", + "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", + "glossaries.presets.finance.title": "Finance / Comptabilité", + "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", + "glossaries.presets.marketing.title": "Marketing / Publicité", + "glossaries.presets.marketing.desc": "Digital, branding, analytics", + "glossaries.presets.hr.title": "RH / Ressources Humaines", + "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", + "glossaries.presets.scientific.title": "Scientifique / Recherche", + "glossaries.presets.scientific.desc": "Publications, thèses, articles", + "glossaries.presets.ecommerce.title": "E-commerce / Vente", + "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", + "glossaries.grid.title": "Vos", + "glossaries.grid.titleHighlight": "glossaires", + "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", + "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", + "glossaries.grid.activeTranslation": "Traduction active :", + "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", + "glossaries.badge.compatible": "Compatible", + "glossaries.badge.otherTarget": "Autre cible", + "glossaries.card.editTerms": "Modifier les termes", + "glossaries.card.created": "생성됨", + "glossaries.card.term": "용어", + "glossaries.card.delete": "Supprimer", + "glossaries.grid.searchPlaceholder": "Search a glossary…", + "glossaries.grid.noResults": "No results for this search.", + "glossaries.detail.backToList": "Back to glossaries", + "glossaries.detail.save": "Save", + "glossaries.detail.savedTitle": "Saved", + "glossaries.detail.savedDesc": "The glossary has been updated.", + "glossaries.detail.settingsTitle": "Settings", + "glossaries.detail.sourceLang": "Source language", + "glossaries.detail.targetLang": "Target language", + "glossaries.detail.termsTitle": "Terms", + "glossaries.detail.terms": "terms", + "glossaries.detail.searchTerms": "Filter…", + "glossaries.detail.noTerms": "No terms yet.", + "glossaries.detail.addFirstTerm": "Add the first term", + "glossaries.detail.addTerm": "Add a term", + "glossaries.detail.maxReached": "Maximum limit reached", + "glossaries.detail.source": "Source", + "glossaries.detail.target": "Target", + "glossaries.detail.sourcePlaceholder": "source term", + "glossaries.detail.targetPlaceholder": "target term", + "glossaries.detail.csvTitle": "CSV", + "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", + "glossaries.detail.export": "Export", + "glossaries.detail.import": "Import", + "glossaries.detail.dangerTitle": "Danger zone", + "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", + "glossaries.detail.deleteGlossary": "Delete this glossary", + "glossaries.detail.confirmDelete": "Confirm deletion?", + "glossaries.detail.confirm": "Confirm", + "glossaries.detail.cancel": "Cancel", + "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", + "glossaries.detail.sourceLocked": "fixed", + "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", + "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", + "glossaries.detail.notFoundTitle": "Glossary not found", + "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", + "glossaries.detail.maxTermsTitle": "Limit reached", + "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", + "glossaries.detail.importEmptyTitle": "Empty file", + "glossaries.detail.importEmptyDesc": "No terms detected in this file.", + "glossaries.detail.importedTitle": "Imported", + "glossaries.detail.importedDesc": "{count} terms imported.", + "glossaries.detail.importErrorTitle": "Read error", + "glossaries.detail.importErrorDesc": "Unable to read the file." +} diff --git a/frontend/src/lib/i18n/messages/ko/index.ts b/frontend/src/lib/i18n/messages/ko/index.ts new file mode 100644 index 0000000..eacc98a --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/index.ts @@ -0,0 +1,60 @@ +// Auto-generated by scripts/generate_i18n_index.py +// Merges all namespace JSON files for locale "ko". + +import admin from "./admin.json"; +import apiKeys from "./apiKeys.json"; +import auth from "./auth.json"; +import checkout from "./checkout.json"; +import common from "./common.json"; +import context from "./context.json"; +import cookieConsent from "./cookieConsent.json"; +import dashboard from "./dashboard.json"; +import fileUploader from "./fileUploader.json"; +import forgotPassword from "./forgotPassword.json"; +import glossaries from "./glossaries.json"; +import landing from "./landing.json"; +import langSelector from "./langSelector.json"; +import layout from "./layout.json"; +import login from "./login.json"; +import memento from "./memento.json"; +import pricing from "./pricing.json"; +import profile from "./profile.json"; +import providerSelector from "./providerSelector.json"; +import providerTheme from "./providerTheme.json"; +import register from "./register.json"; +import resetPassword from "./resetPassword.json"; +import services from "./services.json"; +import settings from "./settings.json"; +import translate from "./translate.json"; +import translateComplete from "./translateComplete.json"; + +const messages: Record = { + ...admin, + ...apiKeys, + ...auth, + ...checkout, + ...common, + ...context, + ...cookieConsent, + ...dashboard, + ...fileUploader, + ...forgotPassword, + ...glossaries, + ...landing, + ...langSelector, + ...layout, + ...login, + ...memento, + ...pricing, + ...profile, + ...providerSelector, + ...providerTheme, + ...register, + ...resetPassword, + ...services, + ...settings, + ...translate, + ...translateComplete, +}; + +export default messages; diff --git a/frontend/src/lib/i18n/messages/ko/landing.json b/frontend/src/lib/i18n/messages/ko/landing.json new file mode 100644 index 0000000..884d53d --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/landing.json @@ -0,0 +1,146 @@ +{ + "landing.nav.why": "왜 우리인가요?", + "landing.nav.formats": "지원 형식", + "landing.nav.pricing": "요금제", + "landing.nav.login": "로그인", + "landing.nav.startFree": "무료 시작", + "landing.hero.tag": "전문 문서 AI", + "landing.hero.titleLine1": "문서를 번역하세요.", + "landing.hero.titleLine2": "서식은 완벽하게 유지.", + "landing.hero.description": "SmartArt, 차트, 목차, 도형 및 복잡한 레이아웃을 원본 그대로 보존하는 유일한 번역기입니다.", + "landing.hero.ctaMain": "무료 시작 — 월 2개 문서", + "landing.hero.ctaSec": "플랜 보기", + "landing.hero.deleted": "파일은 60분 후 삭제", + "landing.hero.noHidden": "숨겨진 비용 없음", + "landing.hero.preview": "결제 전 미리보기", + "landing.hero.formattedOk": "서식 OK", + "landing.hero.aiActive": "AI 번역 활성", + "landing.steps.title": "어떻게 작동하나요?", + "landing.steps.subtitle": "3단계. 서식 손실 제로.", + "landing.steps.step1.num": "01", + "landing.steps.step1.title": "파일 업로드", + "landing.steps.step1.desc": "Excel, Word, PowerPoint 또는 PDF 문서를 드래그 앤 드롭하세요.", + "landing.steps.step2.num": "02", + "landing.steps.step2.title": "언어 및 엔진 선택", + "landing.steps.step2.desc": "대상 언어와 엔진을 선택하세요 — 클래식 또는 컨텍스트 인식 AI.", + "landing.steps.step3.num": "03", + "landing.steps.step3.title": "결과 다운로드", + "landing.steps.step3.desc": "원본과 동일한 서식의 번역 문서를 받으세요.", + "landing.features.tag": "AI 번역 엔진", + "landing.features.title": "당신의 전문성을 이해하는 번역", + "landing.features.description": "AI 모델이 컨텍스트를 분석하고, 전문 용어를 존중하며, 이미지 내 텍스트까지 번역합니다.", + "landing.features.context.title": "산업 컨텍스트", + "landing.features.context.desc": "분야를 설명하면 일반적인 번역이 아닌 맞춤형 번역을 받습니다.", + "landing.features.glossary.title": "산업 용어집", + "landing.features.glossary.desc": "전문 용어를 정의하세요. CTA는 'Call To Action'이 아닌 '공기처리장치'로 유지됩니다.", + "landing.features.vision.title": "이미지 인식", + "landing.features.vision.desc": "이미지, 다이어그램, 차트에 포함된 텍스트를 감지하고 번역합니다.", + "landing.features.demo.source": "원문 (FR)", + "landing.features.demo.google": "Google 번역", + "landing.features.demo.ours": "당사 AI", + "landing.layout.title": "당신의 서식,", + "landing.layout.title2": "완벽하게 보존", + "landing.layout.subtitle": "다른 번역기는 레이아웃을 망칩니다. 우리는 다릅니다.", + "landing.layout.p1.title": "SmartArt 및 다이어그램", + "landing.layout.p1.desc": "조직도, 순서도, 계층도 — 모두 동일하게 번역.", + "landing.layout.p2.title": "목차", + "landing.layout.p2.desc": "목차 항목, 페이지 번호, 상호 참조가 올바르게 업데이트됩니다.", + "landing.layout.p3.title": "차트 및 그래프", + "landing.layout.p3.desc": "제목, 축 레이블, 범례 및 시리즈 이름 — 모두 번역됩니다.", + "landing.layout.p4.title": "도형 및 텍스트 상자", + "landing.layout.p4.desc": "사각형, 둥근 블록, 설명선 — 모든 곳에 로컬라이징.", + "landing.layout.p5.title": "머리글 및 바닥글", + "landing.layout.p5.desc": "머리글, 바닥글, 각주가 절대 누락되지 않습니다.", + "landing.layout.p6.title": "130개 이상의 언어", + "landing.layout.p6.desc": "Google 번역, DeepL 및 전문급 AI 엔진.", + "landing.formats.title": "모든 형식,", + "landing.formats.title2": "모든 요소", + "landing.formats.subtitle": "다른 곳에서 놓치는 부분까지 번역합니다. 비즈니스에 흠잡을 데 없는 문서를.", + "landing.formats.word.name": "Word", + "landing.formats.word.i1": "단락 및 제목", + "landing.formats.word.i2": "표 및 차트", + "landing.formats.word.i3": "SmartArt 다이어그램", + "landing.formats.word.i4": "목차", + "landing.formats.word.i5": "머리글 및 바닥글", + "landing.formats.word.i6": "도형 및 텍스트 상자", + "landing.formats.word.i7": "각주 및 미주", + "landing.formats.excel.name": "Excel", + "landing.formats.excel.i1": "셀 값", + "landing.formats.excel.i2": "시트 이름", + "landing.formats.excel.i3": "차트 및 레이블", + "landing.formats.excel.i4": "머리글 및 바닥글", + "landing.formats.excel.i5": "병합된 셀 유지", + "landing.formats.pptx.name": "PowerPoint", + "landing.formats.pptx.i1": "슬라이드 텍스트 및 메모", + "landing.formats.pptx.i2": "차트 및 다이어그램", + "landing.formats.pptx.i3": "도형 및 텍스트 상자", + "landing.formats.pptx.i4": "마스터 레이아웃", + "landing.formats.pptx.i5": "애니메이션 유지", + "landing.formats.pdf.name": "PDF", + "landing.formats.pdf.i1": "텍스트 기반 PDF", + "landing.formats.pdf.i2": "레이아웃 유지", + "landing.formats.pdf.i3": "이미지 제자리 유지", + "landing.formats.pdf.i4": "표 유지", + "landing.formats.pdf.i5": "DOCX 또는 PDF로 출력", + "landing.pricing.title": "간단하고 투명한 가격", + "landing.pricing.subtitle": "보이는 가격이 지불하실 금액입니다. 숨겨진 비용 없음.", + "landing.pricing.monthly": "월간", + "landing.pricing.annual": "연간", + "landing.pricing.bestValue": "가장 인기", + "landing.pricing.month": "/월", + "landing.pricing.footer": "표시된 가격이 지불하실 금액입니다. 번역 후 추가 비용 없음.", + "landing.pricing.starter.name": "Starter", + "landing.pricing.starter.desc": "개인 및 소규모 프로젝트용", + "landing.pricing.starter.f1": "월 50개 문서", + "landing.pricing.starter.f2": "문서당 최대 50페이지", + "landing.pricing.starter.f3": "Google 번역 + DeepL", + "landing.pricing.starter.f4": "최대 10 MB 파일", + "landing.pricing.starter.cta": "시작하기", + "landing.pricing.pro.name": "Pro", + "landing.pricing.pro.desc": "전문가용", + "landing.pricing.pro.f1": "월 200개 문서", + "landing.pricing.pro.f2": "문서당 최대 200페이지", + "landing.pricing.pro.f3": "AI 번역", + "landing.pricing.pro.f4": "Google + DeepL 포함", + "landing.pricing.pro.f5": "맞춤 용어집 및 프롬프트", + "landing.pricing.pro.f6": "우선 지원", + "landing.pricing.pro.cta": "Pro 체험", + "landing.pricing.business.name": "비즈니스", + "landing.pricing.business.desc": "대용량이 필요한 팀용", + "landing.pricing.business.f1": "월 1,000개 문서", + "landing.pricing.business.f2": "문서당 최대 500페이지", + "landing.pricing.business.f3": "프리미엄 AI (Claude)", + "landing.pricing.business.f4": "모든 제공자 + API", + "landing.pricing.business.f5": "웹훅 및 자동화", + "landing.pricing.business.f6": "팀 시트 5석", + "landing.pricing.business.cta": "문의하기", + "landing.cta.title": "30초 만에 번역 시작", + "landing.cta.subtitle": "신용카드 불필요. 지금 무료로 체험하고 다국어 문서에 새 생명을 불어넣으세요.", + "landing.cta.button": "무료 계정 만들기", + "landing.cta.secure": "AES-256 암호화로 보호", + "landing.footer.desc": "지능형 문서 번역 전문. 레이아웃의 예술과 컨텍스트 AI의 과학을 융합합니다.", + "landing.footer.product": "제품", + "landing.footer.resources": "리소스", + "landing.footer.legal": "법적 고지", + "landing.footer.rights": "© 2026 Wordly.art — All rights reserved.", + "landing.hero.contextEngine": "번역 감지됨: HVAC 시스템 기술 유지보수 용어...", + "landing.hero.liveAnalysis": "실시간 분석", + "landing.hero.termsDetected": "개 용어 감지됨", + "landing.steps.process": "프로세스", + "landing.translate.newProject": "새 프로젝트", + "landing.translate.title": "문서 번역", + "landing.translate.subtitle": "파일을 가져오고 대상 언어를 선택하세요", + "landing.translate.sourceDocument": "원본 문서", + "landing.translate.configuration": "설정", + "landing.translate.sourceLang": "원본 언어", + "landing.translate.targetLang": "대상 언어", + "landing.translate.provider": "제공자", + "landing.translate.startTranslation": "번역 시작", + "landing.translate.zeroRetention": "제로 보관", + "landing.translate.filesDeleted": "처리 후 파일 삭제됨", + "landing.translate.dropHere": "여기에 드래그 앤 드롭", + "landing.translate.supportedFormats": "DOCX, XLSX, PPTX 또는 PDF 파일 지원", + "landing.translate.aiAnalysis": "AI 분석 활성", + "landing.translate.processing": "처리 중", + "landing.translate.preservingLayout": "레이아웃이 보존되고 있습니다" +} diff --git a/frontend/src/lib/i18n/messages/ko/langSelector.json b/frontend/src/lib/i18n/messages/ko/langSelector.json new file mode 100644 index 0000000..63336c2 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/langSelector.json @@ -0,0 +1,7 @@ +{ + "langSelector.search": "검색…", + "langSelector.noResults": "결과 없음", + "langSelector.source": "원본", + "langSelector.target": "대상", + "langSelector.swap": "교환" +} diff --git a/frontend/src/lib/i18n/messages/ko/layout.json b/frontend/src/lib/i18n/messages/ko/layout.json new file mode 100644 index 0000000..bc92e00 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/layout.json @@ -0,0 +1,5 @@ +{ + "layout.nav.apiAccess": "API 액세스", + "layout.footer.terms": "약관", + "layout.footer.privacy": "개인정보" +} diff --git a/frontend/src/lib/i18n/messages/ko/login.json b/frontend/src/lib/i18n/messages/ko/login.json new file mode 100644 index 0000000..474f444 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/login.json @@ -0,0 +1,16 @@ +{ + "login.signInToContinue": "Sign in to continue translating", + "login.email": "Email", + "login.emailPlaceholder": "you@example.com", + "login.password": "Password", + "login.forgotPassword": "Forgot password?", + "login.passwordPlaceholder": "••••••••", + "login.signingIn": "Signing in...", + "login.signIn": "Sign In", + "login.noAccount": "Don't have an account?", + "login.signUpFree": "Sign up for free", + "login.orContinueWith": "또는 이메일로 계속", + "login.google.connecting": "연결 중…", + "login.google.errorGeneric": "Google 로그인 중 문제가 발생했습니다.", + "login.google.errorFailed": "Google 로그인에 실패했습니다. 다시 시도해 주세요." +} diff --git a/frontend/src/lib/i18n/messages/ko/memento.json b/frontend/src/lib/i18n/messages/ko/memento.json new file mode 100644 index 0000000..053d3bd --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/memento.json @@ -0,0 +1,6 @@ +{ + "memento.title": "Momento 발견하기", + "memento.slogan": "Momento는 단순한 메모 앱이 아닙니다. 6개의 AI 에이전트와 최첨단 시맨틱 검색을 사용하여 아이디어를 실시간으로 연결, 분석, 발전시키는 지능형 생태계입니다.", + "memento.ctaFree": "무료로 시작", + "memento.ctaMore": "자세히 보기" +} diff --git a/frontend/src/lib/i18n/messages/ko/pricing.json b/frontend/src/lib/i18n/messages/ko/pricing.json new file mode 100644 index 0000000..d44c303 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/pricing.json @@ -0,0 +1,151 @@ +{ + "pricing.nav.back": "뒤로", + "pricing.nav.home": "홈", + "pricing.nav.mySubscription": "내 구독", + "pricing.header.badge": "AI 모델 업데이트 — 2026년 3월", + "pricing.header.title": "모든 요구에 맞는 플랜", + "pricing.header.subtitle": "원본 레이아웃을 유지하면서 Word, Excel, PowerPoint 문서를 번역하세요. API 키 불필요.", + "pricing.billing.monthly": "월간", + "pricing.billing.yearly": "연간", + "pricing.plans.free.name": "무료", + "pricing.plans.starter.name": "Starter", + "pricing.plans.pro.name": "Pro", + "pricing.plans.business.name": "Business", + "pricing.plans.enterprise.name": "Enterprise", + "pricing.plans.free.description": "앱을 체험하기에 완벽", + "pricing.plans.starter.description": "개인 및 소규모 프로젝트용", + "pricing.plans.pro.description": "전문가 및 성장 중인 팀용", + "pricing.plans.business.description": "팀 및 조직용", + "pricing.plans.enterprise.description": "대규모 조직을 위한 맞춤 솔루션", + "pricing.plans.pro.highlight": "가장 인기", + "pricing.plans.pro.badge": "인기", + "pricing.plans.enterprise.badge": "문의 필요", + "pricing.plans.free.feat1": "월 5개 문서", + "pricing.plans.free.feat2": "문서당 최대 15페이지", + "pricing.plans.free.feat3": "Google 번역 포함", + "pricing.plans.free.feat4": "모든 언어 (130+)", + "pricing.plans.free.feat5": "커뮤니티 지원", + "pricing.plans.starter.feat1": "월 50개 문서", + "pricing.plans.starter.feat2": "문서당 최대 50페이지", + "pricing.plans.starter.feat3": "Google 번역 + DeepL", + "pricing.plans.starter.feat4": "최대 10 MB 파일", + "pricing.plans.starter.feat5": "이메일 지원", + "pricing.plans.starter.feat6": "30일 기록", + "pricing.plans.pro.feat1": "월 200개 문서", + "pricing.plans.pro.feat2": "문서당 최대 200페이지", + "pricing.plans.pro.feat3": "Essential AI 번역", + "pricing.plans.pro.feat4": "Google 번역 + DeepL", + "pricing.plans.pro.feat5": "최대 25 MB 파일", + "pricing.plans.pro.feat6": "사용자 지정 용어집", + "pricing.plans.pro.feat7": "우선 지원", + "pricing.plans.pro.feat8": "90일 기록", + "pricing.plans.business.feat1": "월 1,000개 문서", + "pricing.plans.business.feat2": "문서당 최대 500페이지", + "pricing.plans.business.feat3": "에센셜 + 프리미엄 AI (Claude Haiku)", + "pricing.plans.business.feat4": "모든 번역 제공업체", + "pricing.plans.business.feat5": "최대 50 MB 파일", + "pricing.plans.business.feat6": "API 액세스 (월 10,000회 호출)", + "pricing.plans.business.feat7": "알림 웹훅", + "pricing.plans.business.feat8": "전담 지원", + "pricing.plans.business.feat9": "1년 기록", + "pricing.plans.business.feat10": "고급 분석", + "pricing.plans.enterprise.feat1": "무제한 문서", + "pricing.plans.enterprise.feat2": "모든 AI 모델 (GPT-5, Claude Opus 4.6…)", + "pricing.plans.enterprise.feat3": "온프레미스 또는 전용 클라우드 배포", + "pricing.plans.enterprise.feat4": "99.9% SLA 보장", + "pricing.plans.enterprise.feat5": "24/7 전담 지원", + "pricing.plans.enterprise.feat6": "화이트라벨", + "pricing.plans.enterprise.feat7": "무제한 팀", + "pricing.plans.enterprise.feat8": "맞춤 연동", + "pricing.card.onRequest": "문의 필요", + "pricing.card.free": "무료", + "pricing.card.perMonth": "/월", + "pricing.card.billedYearly": "연 {price} € 청구", + "pricing.card.documents": "문서", + "pricing.card.pagesMax": "최대 페이지", + "pricing.card.aiTranslation": "AI 번역", + "pricing.card.unlimited": "무제한", + "pricing.card.perMonthStat": "/ 월", + "pricing.card.perDoc": "p / 문서", + "pricing.card.aiEssential": "에센셜", + "pricing.card.aiEssentialPremium": "에센셜 + 프리미엄", + "pricing.card.aiCustom": "맞춤", + "pricing.card.myPlan": "내 플랜", + "pricing.card.managePlan": "플랜 관리", + "pricing.card.startFree": "무료로 시작", + "pricing.card.contactUs": "문의하기", + "pricing.card.choosePlan": "이 플랜 선택", + "pricing.card.processing": "처리 중…", + "pricing.comparison.title": "상세 비교", + "pricing.comparison.subtitle": "각 플랜에 포함된 모든 기능", + "pricing.comparison.feature": "기능", + "pricing.comparison.docsPerMonth": "문서 / 월", + "pricing.comparison.pagesMaxPerDoc": "최대 페이지 / 문서", + "pricing.comparison.maxFileSize": "최대 파일 크기", + "pricing.comparison.googleTranslation": "Google 번역", + "pricing.comparison.deepl": "DeepL", + "pricing.comparison.aiEssential": "에센셜 AI 번역", + "pricing.comparison.aiPremium": "프리미엄 AI 번역", + "pricing.comparison.apiAccess": "API 액세스", + "pricing.comparison.priorityProcessing": "우선 처리", + "pricing.comparison.support": "지원", + "pricing.comparison.support.community": "커뮤니티", + "pricing.comparison.support.email": "이메일", + "pricing.comparison.support.priority": "우선", + "pricing.comparison.support.dedicated": "전담", + "pricing.comparison.mb": "MB", + "pricing.credits.title": "추가 크레딧", + "pricing.credits.subtitle": "더 필요하세요? 구독 없이 크레딧을 개별 구매하세요.", + "pricing.credits.perPage": "1 크레딧 = 1번역 페이지.", + "pricing.credits.bestValue": "최고 가성비", + "pricing.credits.unit": "크레딧", + "pricing.credits.centsPerCredit": "센트 / 크레딧", + "pricing.credits.buy": "구매", + "pricing.trust.encryption.title": "종단간 암호화", + "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 (저장 시)", + "pricing.trust.languages.title": "130+개 언어", + "pricing.trust.languages.sub": "아랍어, 페르시아어, 히브리어 (RTL) 포함", + "pricing.trust.parallel.title": "병렬 처리", + "pricing.trust.parallel.sub": "초고속 멀티스레드 AI", + "pricing.trust.availability.title": "24/7 이용 가능", + "pricing.trust.availability.sub": "99.9% 가동 보장", + "pricing.aiModels.title": "AI 모델 — 2026년 3월", + "pricing.aiModels.essential.title": "에센셜 AI 번역", + "pricing.aiModels.essential.plan": "Pro 플랜", + "pricing.aiModels.essential.descPrefix": "기반:", + "pricing.aiModels.essential.descSuffix": "— 2026년 가장 비용 효율적인 AI 모델. 프론티어 모델과 동등한 품질을 극소수의 비용으로 제공.", + "pricing.aiModels.essential.modelName": "Essential AI 모델", + "pricing.aiModels.essential.context": "163K 토큰 컨텍스트", + "pricing.aiModels.essential.value": "우수한 가성비", + "pricing.aiModels.premium.title": "프리미엄 AI 번역", + "pricing.aiModels.premium.plan": "Business 플랜", + "pricing.aiModels.premium.descPrefix": "기반:", + "pricing.aiModels.premium.descSuffix": "Anthropic사 제품 — 법률, 의료 및 복잡한 기술 문서에서 높은 정확도.", + "pricing.aiModels.premium.context": "200K 토큰 컨텍스트", + "pricing.aiModels.premium.precision": "최고 정확도", + "pricing.faq.title": "자주 묻는 질문", + "pricing.faq.q1": "언제든지 플랜을 변경할 수 있나요?", + "pricing.faq.a1": "네. 업그레이드는 즉시 적용되며 일할 계산됩니다. 다운그레이드는 현재 기간 종료 시 적용됩니다.", + "pricing.faq.q2": "「에센셜 AI 번역」이란 무엇인가요?", + "pricing.faq.a2": "당사의 AI 엔진입니다. 문서의 맥락을 이해하고, 레이아웃을 보존하며, 기술 용어를 기존 번역보다 훨씬 잘 처리합니다.", + "pricing.faq.q3": "에센셜 AI와 프리미엄 AI의 차이점은 무엇인가요?", + "pricing.faq.a3": "Essential AI는 최적화된 모델을 사용합니다 (우수한 가성비). Premium AI는 Anthropic의 Claude 3.5 Haiku를 사용하여 법률, 의료 및 복잡한 기술 문서에서 더 정확합니다.", + "pricing.faq.q4": "번역 후 문서가 보관되나요?", + "pricing.faq.a4": "번역된 파일은 플랜에 따라 이용 가능합니다 (Starter 30일, Pro 90일, Business 1년). 저장 시 및 전송 중 암호화됩니다.", + "pricing.faq.q5": "월간 할당량을 초과하면 어떻게 되나요?", + "pricing.faq.a5": "추가 크레딧을 개별 구매하거나 플랜을 업그레이드할 수 있습니다. 사용량이 80%에 도달하면 알림을 받습니다.", + "pricing.faq.q6": "유료 플랜의 무료 체험이 있나요?", + "pricing.faq.a6": "무료 플랜은 영구적이며 신용카드가 필요 없습니다. Pro 및 Business 플랜의 경우 14일 체험을 위해 문의해 주세요.", + "pricing.faq.q7": "어떤 파일 형식을 지원하나요?", + "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx), 그리고 곧 PDF. 모든 플랜에서 동일한 형식을 지원합니다.", + "pricing.cta.title": "시작할 준비가 되셨나요?", + "pricing.cta.subtitle": "신용카드 없이 무료로 시작하세요. 필요할 때 업그레이드하세요.", + "pricing.cta.createAccount": "무료 계정 만들기", + "pricing.cta.login": "로그인", + "pricing.toast.demo": "데모 모드 — Stripe가 아직 구성되지 않았습니다. 프로덕션에서는 결제 페이지로 리디렉션되어 {planId} 플랜을 활성화합니다.", + "pricing.toast.networkError": "네트워크 오류. 다시 시도해 주세요.", + "pricing.toast.paymentError": "결제 생성 중 오류가 발생했습니다.", + "pricing.dashboard": "대시보드", + "pricing.okSymbol": "✓", + "pricing.errSymbol": "✕" +} diff --git a/frontend/src/lib/i18n/messages/ko/profile.json b/frontend/src/lib/i18n/messages/ko/profile.json new file mode 100644 index 0000000..449ae7e --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/profile.json @@ -0,0 +1,58 @@ +{ + "profile.header.title": "내 프로필", + "profile.header.subtitle": "계정 및 환경설정을 관리합니다.", + "profile.tabs.account": "계정", + "profile.tabs.subscription": "구독", + "profile.tabs.preferences": "환경설정", + "profile.account.user": "사용자", + "profile.account.memberSince": "가입일", + "profile.plan.label": "플랜", + "profile.plan.free": "Free", + "profile.plan.starter": "Starter", + "profile.plan.pro": "Pro", + "profile.plan.business": "Business", + "profile.plan.enterprise": "Enterprise", + "profile.plan.pricePerMonth": "{price} €/월", + "profile.subscription.canceling": "취소 중", + "profile.subscription.active": "활성", + "profile.subscription.unknown": "알 수 없음", + "profile.subscription.accessUntil": "접근 가능 기한", + "profile.subscription.renewalOn": "갱신일", + "profile.subscription.upgradePlan": "유료 플랜으로 업그레이드", + "profile.subscription.changePlan": "플랜 변경", + "profile.subscription.manageBilling": "결제 관리", + "profile.subscription.billingUnavailable": "결제 포털을 사용할 수 없습니다.", + "profile.subscription.billingError": "결제 포털에 접근하는 중 오류가 발생했습니다.", + "profile.subscription.cancelSuccess": "구독이 취소되었습니다. 기간 종료까지 접근할 수 있습니다.", + "profile.subscription.cancelError": "취소 중 오류가 발생했습니다.", + "profile.subscription.networkError": "네트워크 오류.", + "profile.usage.title": "이번 달 사용량", + "profile.usage.resetOn": "초기화일", + "profile.usage.documents": "문서", + "profile.usage.pages": "페이지", + "profile.usage.extraCredits": "추가 크레딧", + "profile.usage.extraCreditsPlural": "추가 크레딧", + "profile.usage.quotaReached": "할당량 초과", + "profile.usage.quotaReachedDesc": "계속 사용하려면 상위 플랜으로 업그레이드하세요.", + "profile.usage.unlockMore": "유료 플랜으로 더 많은 번역을 사용하세요.", + "profile.usage.viewPlans": "플랜 보기", + "profile.usage.includedInPlan": "플랜에 포함됨", + "profile.danger.title": "위험 구역", + "profile.danger.description": "취소는 현재 기간이 끝나면 적용됩니다. 해당 날짜까지 접근이 유지됩니다.", + "profile.danger.confirm": "정말 진행하시겠습니까? 이 작업은 되돌릴 수 없습니다.", + "profile.danger.confirmCancel": "취소 확인", + "profile.danger.cancelSubscription": "구독 취소", + "profile.danger.keep": "아니요, 유지합니다", + "profile.prefs.interfaceLang": "인터페이스 언어", + "profile.prefs.interfaceLangDesc": "브라우저 설정에 따라 언어가 자동 감지됩니다. 수동으로 변경할 수도 있습니다.", + "profile.prefs.defaultTargetLang": "기본 번역 대상 언어", + "profile.prefs.selectLanguage": "언어 선택", + "profile.prefs.defaultTargetLangDesc": "이 언어가 번역 시 자동으로 선택됩니다.", + "profile.prefs.save": "저장", + "profile.prefs.theme": "테마", + "profile.prefs.themeDesc": "인터페이스 외모를 선택하세요", + "profile.prefs.cache": "캐시", + "profile.prefs.cacheDesc": "로컬 캐시를 지우면 일부 표시 문제가 해결될 수 있습니다.", + "profile.prefs.clearing": "지우는 중...", + "profile.prefs.clearCache": "캐시 지우기" +} diff --git a/frontend/src/lib/i18n/messages/ko/providerSelector.json b/frontend/src/lib/i18n/messages/ko/providerSelector.json new file mode 100644 index 0000000..6730e49 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/providerSelector.json @@ -0,0 +1,7 @@ +{ + "providerSelector.noClassic": "사용 가능한 표준 번역기가 없습니다.", + "providerSelector.noLlm": "구성된 AI 모델이 없습니다.", + "providerSelector.costOne": "비용: 페이지당 1 크레딧", + "providerSelector.costFive": "비용: 페이지당 5 크레딧 (프리미엄 요율)", + "providerSelector.unlockContextual": "전체 문서를 위한 프리미엄 컨텍스트 번역 잠금 해제." +} diff --git a/frontend/src/lib/i18n/messages/ko/providerTheme.json b/frontend/src/lib/i18n/messages/ko/providerTheme.json new file mode 100644 index 0000000..310f6e6 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/providerTheme.json @@ -0,0 +1,29 @@ +{ + "providerTheme.deepseek.badge": "필수", + "providerTheme.deepseek.subBadge": "기술 및 경제", + "providerTheme.deepseek.desc": "초정밀 경제적 번역. 기술 문서 및 코드에 이상적.", + "providerTheme.openai.badge": "프리미엄", + "providerTheme.openai.subBadge": "고충실도", + "providerTheme.openai.desc": "세계적 AI 표준. 최대 텍스트 일관성과 엄격한 스타일 준수.", + "providerTheme.minimax.badge": "고급", + "providerTheme.minimax.subBadge": "성능", + "providerTheme.minimax.desc": "놀라운 실행 속도와 복잡한 구조에 대한 뛰어난 이해.", + "providerTheme.openrouter.badge": "익스프레스", + "providerTheme.openrouter.subBadge": "멀티 모델", + "providerTheme.openrouter.desc": "번역에 최적화된 최고의 오픈소스 모델에 대한 통합 액세스.", + "providerTheme.openrouter_premium.badge": "울트라", + "providerTheme.openrouter_premium.subBadge": "최대 컨텍스트", + "providerTheme.openrouter_premium.desc": "최신 모델(GPT-4o, Claude Sonnet 4.6)의 지원을 받는 긴 문서 번역.", + "providerTheme.zai.badge": "전문", + "providerTheme.zai.subBadge": "금융 및 법률", + "providerTheme.zai.desc": "까다로운 비즈니스 용어(법률, 금융)에 맞게 미세 조정된 모델.", + "providerTheme.default.badge": "모던", + "providerTheme.default.subBadge": "AI 추론", + "providerTheme.default.desc": "대규모 언어 모델(LLM) 번역, 고급 의미 분석 포함.", + "providerTheme.classic.google.label": "Google 번역", + "providerTheme.classic.google.desc": "130개 이상의 언어를 지원하는 초고속 번역. 일반적인 워크플로에 권장.", + "providerTheme.classic.deepl.label": "DeepL Pro", + "providerTheme.classic.deepl.desc": "유창함과 자연스러운 표현으로 유명한 고정밀 번역.", + "providerTheme.classic.google_cloud.label": "Google Cloud API", + "providerTheme.classic.google_cloud.desc": "대용량 문서 처리에 최적화된 전문 클라우드 엔진." +} diff --git a/frontend/src/lib/i18n/messages/ko/register.json b/frontend/src/lib/i18n/messages/ko/register.json new file mode 100644 index 0000000..bcc5717 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/register.json @@ -0,0 +1,29 @@ +{ + "register.title": "계정 만들기", + "register.subtitle": "무료로 번역 시작", + "register.error.failed": "가입 실패", + "register.name.label": "이름", + "register.name.placeholder": "이름을 입력하세요", + "register.name.error": "이름은 최소 2자 이상이어야 합니다", + "register.email.label": "이메일 주소", + "register.email.placeholder": "you@example.com", + "register.email.error": "유효하지 않은 이메일 주소", + "register.password.label": "비밀번호", + "register.password.error": "비밀번호는 8자 이상이며 대문자, 소문자, 숫자를 각각 하나 이상 포함해야 합니다", + "register.password.show": "비밀번호 표시", + "register.password.hide": "비밀번호 숨기기", + "register.password.strengthLabel": "강도:", + "register.password.strength.weak": "약함", + "register.password.strength.medium": "보통", + "register.password.strength.strong": "강함", + "register.confirmPassword.label": "비밀번호 확인", + "register.confirmPassword.error": "비밀번호가 일치하지 않습니다", + "register.confirmPassword.show": "표시", + "register.confirmPassword.hide": "숨기기", + "register.submit.creating": "계정 생성 중...", + "register.submit.create": "계정 만들기", + "register.hasAccount": "이미 계정이 있으신가요?", + "register.login": "로그인", + "register.terms.prefix": "계정을 만들면 당사의", + "register.terms.link": "서비스 약관에 동의하게 됩니다" +} diff --git a/frontend/src/lib/i18n/messages/ko/resetPassword.json b/frontend/src/lib/i18n/messages/ko/resetPassword.json new file mode 100644 index 0000000..680714f --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/resetPassword.json @@ -0,0 +1,22 @@ +{ + "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", + "resetPassword.passwordMismatch": "Passwords do not match", + "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", + "resetPassword.error": "An error occurred", + "resetPassword.invalidLink": "Invalid link", + "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", + "resetPassword.requestNewLink": "Request new link", + "resetPassword.successTitle": "Password reset", + "resetPassword.newPasswordTitle": "New password", + "resetPassword.successSubtitle": "You will be redirected to login", + "resetPassword.subtitle": "Set your new password", + "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", + "resetPassword.newPassword": "New password", + "resetPassword.showPassword": "Show password", + "resetPassword.hidePassword": "Hide password", + "resetPassword.confirmPassword": "Confirm password", + "resetPassword.resetting": "Resetting...", + "resetPassword.resetPassword": "Reset password", + "resetPassword.backToLogin": "Back to login", + "resetPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/ko/services.json b/frontend/src/lib/i18n/messages/ko/services.json new file mode 100644 index 0000000..7edf496 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/services.json @@ -0,0 +1,14 @@ +{ + "services.title": "번역 제공업체", + "services.subtitle": "제공업체는 관리자가 구성합니다. 현재 계정에서 사용 가능한 제공업체를 확인할 수 있습니다.", + "services.loading": "제공업체 로딩 중...", + "services.noProviders": "현재 구성된 제공업체가 없습니다. 관리자에게 문의하세요.", + "services.classic": "클래식 번역", + "services.llmPro": "LLM · 컨텍스트 인식 (Pro)", + "services.available": "사용 가능", + "services.model": "모델", + "services.adminOnly.title": "제공업체 설정은 관리자 전용입니다", + "services.adminOnly.desc": "API 키, 모델 선택, 제공업체 활성화는 관리자가 관리 패널에서 관리합니다. API 키를 입력할 필요가 없습니다.", + "services.fallback.google.label": "Google 번역", + "services.fallback.google.desc": "빠른 번역, 130개 이상의 언어" +} diff --git a/frontend/src/lib/i18n/messages/ko/settings.json b/frontend/src/lib/i18n/messages/ko/settings.json new file mode 100644 index 0000000..3284bfb --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/settings.json @@ -0,0 +1,20 @@ +{ + "settings.title": "설정", + "settings.subtitle": "일반 애플리케이션 설정", + "settings.formats.title": "지원 형식", + "settings.formats.subtitle": "번역 가능한 문서 유형", + "settings.formats.formulas": "수식", + "settings.formats.styles": "스타일", + "settings.formats.images": "이미지", + "settings.formats.headers": "머리글", + "settings.formats.tables": "표", + "settings.formats.slides": "슬라이드", + "settings.formats.notes": "메모", + "settings.cache.title": "캐시", + "settings.cache.desc": "로컬 캐시를 지우면 일부 표시 문제가 해결될 수 있습니다.", + "settings.cache.clearing": "지우는 중...", + "settings.cache.clear": "캐시 지우기", + "settings.formats.excel.name": "Excel", + "settings.formats.word.name": "Word", + "settings.formats.powerpoint.name": "PowerPoint" +} diff --git a/frontend/src/lib/i18n/messages/ko/translate.json b/frontend/src/lib/i18n/messages/ko/translate.json new file mode 100644 index 0000000..dc7d199 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/translate.json @@ -0,0 +1,92 @@ +{ + "translate.mode.label": "Mode de traduction", + "translate.mode.classic": "Classique", + "translate.mode.classicDesc": "Rapide", + "translate.mode.proLlm": "Pro LLM", + "translate.mode.proLlmDesc": "Contextuel", + "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", + "translate.mode.upgradeLink": "Passer à Pro", + "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", + "translate.glossary.title": "용어집", + "translate.glossary.select": "용어집 선택", + "translate.glossary.none": "없음", + "translate.glossary.terms": "개", + "translate.glossary.proOnly": "Pro로 업그레이드하여 용어집 사용", + "translate.glossary.myGlossaries": "내 용어집", + "translate.glossary.fromTemplate": "템플릿에서 만들기", + "translate.glossary.noGlossaryForPair": "용어집 없음", + "translate.glossary.noGlossaries": "용어집 없음", + "translate.glossary.loading": "로딩 중...", + "translate.glossary.classicMode": "용어집 없는 중립 엔진 (AI만)", + "translate.glossary.selectPlaceholder": "용어집 선택...", + "translate.glossary.multilingual": "다국어", + "translate.glossary.noGlossaryAvailable": "사용 가능한 용어집 없음", + "translate.glossary.filterByLang": "언어별 필터", + "translate.glossary.active": "활성", + "translate.glossary.inactive": "비활성", + "translate.glossary.availableTemplates": "사용 가능한 템플릿", + "translate.glossary.importing": "가져오는 중...", + "translate.glossary.imported": "(가져옴)", + "translate.glossary.noGlossaryForSource": "원본 언어에 대한 용어집 또는 템플릿 없음", + "translate.glossary.createGlossary": "용어집 만들기", + "translate.glossary.showAll": "모든 용어집 표시", + "translate.glossary.activePreview": "활성 일치 미리보기:", + "translate.glossary.total": "총", + "translate.glossary.moreTerms": "추가 용어", + "translate.glossary.noTerms": "이 용어집에 용어가 없습니다.", + "translate.glossary.sourceTerm": "원본 용어", + "translate.glossary.translation": "번역", + "translate.glossary.addTerm": "용어 추가", + "translate.glossary.disabledMode": "용어집이 적용되지 않은 중립 엔진", + "translate.glossary.addTermError": "용어 추가 오류", + "translate.glossary.networkError": "네트워크 오류", + "translate.glossary.importFailed": "가져오기 실패 ({status})", + "translate.glossary.helpText": "용어집은 정확한 용어 번역을 강제합니다. 원본 언어가 문서의 원래 언어와 일치하는 용어집을 선택하세요.", + "translate.glossary.sourceWarning": "주의: 이 용어집은 원본 언어를 사용합니다", + "translate.glossary.sourceWarningBut": "하지만 문서가 다음으로 설정되어 있습니다", + "translate.glossary.targetWarning": "대상 불일치: 이 용어집은 다음 언어로 번역하도록 설계되었습니다", + "translate.glossary.targetWarningBut": "하지만 문서의 대상은", + "translate.glossary.targetWarningEnd": "용어가 관련이 없을 수 있습니다.", + "translate.header.processing": "처리 진행 중", + "translate.header.aiActive": "AI 분석 활성", + "translate.header.aiActiveDesc": "레이아웃이 컨텍스트 엔진에 의해 보존되고 있습니다.", + "translate.header.completed": "완료됨", + "translate.header.completedTitle": "번역 완료", + "translate.header.proSpace": "Pro 공간", + "translate.header.translateDoc": "문서 번역", + "translate.header.translateDocDesc": "초고충실도 번역 엔진으로 원본 레이아웃을 유지하세요.", + "translate.upload.nativeFormat": "네이티브 형식", + "translate.fileType.word": "Word (.docx)", + "translate.fileType.excel": "Excel (.xlsx)", + "translate.fileType.slides": "슬라이드 (.pptx)", + "translate.fileType.pdf": "PDF (.pdf)", + "translate.startTranslation": "번역 시작", + "translate.submit": "제출 중…", + "translate.chooseTargetLang": "대상 언어를 선택하세요", + "translate.pleaseLoadFile": "먼저 파일을 업로드하세요", + "translate.contextEngineActive": "컨텍스트 엔진 활성", + "translate.phase1": "1단계: 초기화", + "translate.phase2": "2단계: 컨텍스트 재구성", + "translate.stat.segments": "세그먼트", + "translate.stat.precision": "정밀도", + "translate.stat.speedLabel": "속도", + "translate.stat.turbo": "터보", + "translate.stat.time": "시간", + "translate.complete.masterQuality": "✓ 마스터 품질", + "translate.download": "다운로드", + "translate.newTranslation": "+ 새 번역", + "translate.failedTitle": "번역 오류", + "translate.retry": "재시도", + "translate.uploadAnother": "다른 파일 업로드", + "translate.monitor": "AI 모니터", + "translate.summary": "요약", + "translate.cancelProcess": "⟳ 프로세스 취소", + "translate.layoutIntegrity": "레이아웃 무결성", + "translate.secureHundred": "100% 안전", + "translate.okHundred": "100% OK", + "translate.preserveLayout": "레이아웃 유지", + "translate.preserveLayoutDesc": "레이아웃 유지", + "translate.textOnly": "텍스트만", + "translate.textOnlyDesc": "텍스트만 빠른 번역", + "translate.unavailableStandard": "표준 모드에서 사용 불가 (AI만)" +} diff --git a/frontend/src/lib/i18n/messages/ko/translateComplete.json b/frontend/src/lib/i18n/messages/ko/translateComplete.json new file mode 100644 index 0000000..9e12552 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ko/translateComplete.json @@ -0,0 +1,6 @@ +{ + "translateComplete.highQuality": "고품질", + "translateComplete.segments": "세그먼트", + "translateComplete.characters": "문자", + "translateComplete.confidence": "신뢰도" +} diff --git a/frontend/src/lib/i18n/messages/nl/admin.json b/frontend/src/lib/i18n/messages/nl/admin.json new file mode 100644 index 0000000..53071b2 --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/admin.json @@ -0,0 +1,48 @@ +{ + "admin.login.title": "Beheer", + "admin.login.required": "Inloggen vereist", + "admin.login.password": "Admin-wachtwoord", + "admin.login.connecting": "Verbinden...", + "admin.login.access": "Toegang tot admin-paneel", + "admin.login.restricted": "Alleen voor beheerders", + "admin.layout.checking": "Authenticatie verifiëren...", + "admin.dashboard.title": "Admin Dashboard", + "admin.dashboard.subtitle": "Beheerder controlepaneel", + "admin.dashboard.refresh": "Vernieuwen", + "admin.dashboard.refreshTooltip": "Dashboard-gegevens vernieuwen", + "admin.dashboard.config": "Systeemconfiguratie", + "admin.dashboard.maxFileSize": "Max bestandsgrootte:", + "admin.dashboard.translationService": "Vertaalservice:", + "admin.dashboard.formats": "Formaten:", + "admin.nav.dashboard": "Dashboard", + "admin.nav.users": "Gebruikers", + "admin.nav.pricing": "Prijzen & Stripe", + "admin.nav.providers": "Providers", + "admin.nav.system": "Systeem", + "admin.nav.logs": "Logboeken", + "admin.users.title": "Gebruikersbeheer", + "admin.users.subtitle": "Gebruikersaccounts bekijken en beheren", + "admin.users.planUpdated": "Abonnement bijgewerkt", + "admin.users.planChanged": "Het abonnement is succesvol gewijzigd naar \\\"{plan}\\\".", + "admin.users.unknownError": "Onbekende fout", + "admin.users.error": "Fout", + "admin.users.planUpdateError": "Kan abonnement niet bijwerken: {message}", + "admin.users.noKeys": "Geen sleutels", + "admin.users.noKeysDesc": "Deze gebruiker heeft geen actieve API-sleutels.", + "admin.users.keysRevoked": "Sleutels ingetrokken", + "admin.users.keysRevokedDesc": "{count} API-sleutel(s) succesvol ingetrokken.", + "admin.users.revokeError": "Kan sleutels niet intrekken: {message}", + "admin.users.retry": "Opnieuw proberen", + "admin.system.title": "Systeem", + "admin.system.subtitle": "Systeemstatus bewaken en bronnen beheren", + "admin.system.quotas": "Vertaalquota's", + "admin.system.resetQuotas": "Maandelijkse quota's resetten", + "admin.system.resetting": "Resetten...", + "admin.system.reset": "Resetten", + "admin.system.allOperational": "Alle systemen operationeel", + "admin.system.issuesDetected": "Systeemproblemen gedetecteerd", + "admin.system.waitingData": "Wachten op gegevens...", + "admin.system.purging": "Wissen...", + "admin.system.clean": "Opschonen", + "admin.system.purge": "Wissen" +} diff --git a/frontend/src/lib/i18n/messages/nl/apiKeys.json b/frontend/src/lib/i18n/messages/nl/apiKeys.json new file mode 100644 index 0000000..1d86ec0 --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/apiKeys.json @@ -0,0 +1,72 @@ +{ + "apiKeys.webhook.title": "Intégration Webhook", + "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", + "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", + "apiKeys.webhook.codeParam": "webhook_url", + "apiKeys.title": "API-sleutels", + "apiKeys.subtitle": "Beheer je API-sleutels voor programmatische toegang tot de vertaal-API.", + "apiKeys.loading": "Laden...", + "apiKeys.sectionTitle": "API en automatisering", + "apiKeys.sectionDesc": "Genereer en beheer je API-sleutels voor automatiseringsworkflows", + "apiKeys.keysUsed": "{total} van {max} sleutels gebruikt", + "apiKeys.maxReached": "Maximum aantal sleutels bereikt. Trek een sleutel in om een nieuwe te genereren.", + "apiKeys.canGenerate": "Je kunt nog {count} sleutel genereren", + "apiKeys.canGeneratePlural": "Je kunt nog {count} sleutels genereren", + "apiKeys.generateNew": "Nieuwe sleutel genereren", + "apiKeys.keyRevoked": "Sleutel ingetrokken", + "apiKeys.keyRevokedDesc": "De API-sleutel is succesvol ingetrokken.", + "apiKeys.keyNotFound": "Sleutel niet gevonden", + "apiKeys.keyNotFoundDesc": "De API-sleutel bestaat niet meer. Deze is mogelijk al ingetrokken.", + "apiKeys.error": "Fout", + "apiKeys.revokeError": "Kon de API-sleutel niet intrekken. Probeer opnieuw.", + "apiKeys.limitReached": "Limiet bereikt", + "apiKeys.limitReachedDesc": "Je hebt het maximum van 10 API-sleutels bereikt. Trek een bestaande sleutel in om een nieuwe te genereren.", + "apiKeys.proRequired": "Pro-functie vereist", + "apiKeys.proRequiredDesc": "API-sleutels zijn een Pro-functie. Upgrade je account.", + "apiKeys.generateError": "Kon API-sleutel niet genereren. Probeer opnieuw.", + "apiKeys.upgrade.title": "API-sleutels", + "apiKeys.upgrade.subtitle": "Automatiseer je vertalingen met API-toegang", + "apiKeys.upgrade.feat1": "Genereer onbeperkt API-sleutels", + "apiKeys.upgrade.feat2": "Automatiseer documentvertaling", + "apiKeys.upgrade.feat3": "Webhook-meldingen", + "apiKeys.upgrade.feat4": "LLM-vertaalmodi", + "apiKeys.upgrade.proFeature": "API-sleutels zijn een {pro}-functie. Upgrade om API-automatisering te ontgrendelen.", + "apiKeys.upgrade.pro": "Pro", + "apiKeys.upgrade.cta": "Upgrade naar Pro", + "apiKeys.dialog.maxTitle": "Maximum aantal sleutels bereikt", + "apiKeys.dialog.maxDesc": "Je hebt het maximum van 10 API-sleutels bereikt. Trek een bestaande sleutel in voordat je een nieuwe genereert.", + "apiKeys.dialog.close": "Sluiten", + "apiKeys.dialog.generated": "API-sleutel gegenereerd!", + "apiKeys.dialog.generatedDesc": "Je nieuwe API-sleutel is aangemaakt. Kopieer hem nu - hij wordt niet meer getoond.", + "apiKeys.dialog.important": "Belangrijk:", + "apiKeys.dialog.importantDesc": "Dit is de enige keer dat je deze sleutel ziet. Bewaar hem veilig.", + "apiKeys.dialog.apiKey": "API-sleutel", + "apiKeys.dialog.name": "Naam:", + "apiKeys.dialog.done": "Klaar", + "apiKeys.dialog.copied": "Ik heb de sleutel gekopieerd", + "apiKeys.dialog.generateTitle": "Nieuwe API-sleutel genereren", + "apiKeys.dialog.generateDesc": "Maak een nieuwe API-sleutel aan voor programmatische toegang tot de vertaal-API.", + "apiKeys.dialog.keyName": "Sleutelnaam (optioneel)", + "apiKeys.dialog.keyNamePlaceholder": "bijv. Productie, Staging", + "apiKeys.dialog.keyNameHint": "Een beschrijvende naam om deze sleutel later te herkennen.", + "apiKeys.dialog.nameTooLong": "Naam mag maximaal {max} tekens bevatten", + "apiKeys.dialog.nameInvalid": "Naam mag alleen letters, cijfers, spaties, koppeltekens en underscores bevatten", + "apiKeys.dialog.cancel": "Annuleren", + "apiKeys.dialog.generating": "Genereren...", + "apiKeys.dialog.generate": "Sleutel genereren", + "apiKeys.table.name": "Naam", + "apiKeys.table.prefix": "Voorvoegsel", + "apiKeys.table.created": "Aangemaakt", + "apiKeys.table.lastUsed": "Laatst gebruikt", + "apiKeys.table.never": "Nooit", + "apiKeys.table.actions": "Acties", + "apiKeys.table.revoke": "Intrekken", + "apiKeys.table.copyPrefix": "Sleutelvoorvoegsel kopiëren", + "apiKeys.table.revokeKey": "Sleutel intrekken", + "apiKeys.revokeDialog.title": "API-sleutel intrekken", + "apiKeys.revokeDialog.desc": "Weet je zeker dat je de sleutel \\\"{name}\\\" wilt intrekken? Deze actie kan niet ongedaan worden gemaakt.", + "apiKeys.revokeDialog.confirm": "Ja, intrekken", + "apiKeys.revokeDialog.cancel": "Annuleren", + "apiKeys.noKeysGenerated": "Geen sleutels gegenereerd", + "apiKeys.copied": "Gekopieerd!" +} diff --git a/frontend/src/lib/i18n/messages/nl/auth.json b/frontend/src/lib/i18n/messages/nl/auth.json new file mode 100644 index 0000000..b300370 --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/auth.json @@ -0,0 +1,3 @@ +{ + "auth.brandName": "Wordly" +} diff --git a/frontend/src/lib/i18n/messages/nl/checkout.json b/frontend/src/lib/i18n/messages/nl/checkout.json new file mode 100644 index 0000000..82d605e --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/checkout.json @@ -0,0 +1,12 @@ +{ + "checkout.activating": "Activeren…", + "checkout.activatingDesc": "We werken uw abonnement bij, even geduld.", + "checkout.paymentConfirmed": "Betaling bevestigd!", + "checkout.subscriptionActivated": "Abonnement geactiveerd!", + "checkout.planActivated": "{plan}-abonnement geactiveerd!", + "checkout.redirectingToProfile": "Doorverwijzen naar uw profiel…", + "checkout.paymentReceived": "Betaling ontvangen", + "checkout.redirecting": "Doorverwijzen…", + "checkout.syncError": "Synchronisatiefout", + "checkout.networkError": "Netwerkfout. Uw betaling is bevestigd — vernieuw uw profiel." +} diff --git a/frontend/src/lib/i18n/messages/nl/common.json b/frontend/src/lib/i18n/messages/nl/common.json new file mode 100644 index 0000000..8d83b8d --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/common.json @@ -0,0 +1,4 @@ +{ + "common.loading": "Laden...", + "common.backToHome": "Terug naar home" +} diff --git a/frontend/src/lib/i18n/messages/nl/context.json b/frontend/src/lib/i18n/messages/nl/context.json new file mode 100644 index 0000000..862db7b --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/context.json @@ -0,0 +1,25 @@ +{ + "context.proTitle": "Pro-functie", + "context.proDesc": "Context en professionele woordenlijsten zijn beschikbaar met Pro-, Business- en Enterprise-abonnementen. Ze bieden nauwkeurigere vertalingen via instructies en vocabulair specifiek voor jouw domein.", + "context.viewPlans": "Abonnementen bekijken", + "context.title": "Context en woordenlijst", + "context.subtitle": "Verbeter de vertaalkwaliteit met instructies en vocabulair specifiek voor jouw domein.", + "context.presets.title": "Professionele woordenlijsten", + "context.presets.desc": "Laad een volledige woordenlijst met instructies en gespecialiseerde terminologie", + "context.instructions.title": "Contextinstructies", + "context.instructions.desc": "Instructies die de AI volgt tijdens het vertalen", + "context.instructions.placeholder": "Bijv.: Je vertaalt HVAC-technische documenten. Gebruik nauwkeurige technische terminologie...", + "context.glossary.title": "Technische woordenlijst", + "context.glossary.desc": "Formaat: bron=doel (één per regel). Woordenlijsten geladen via preset zijn bewerkbaar.", + "context.glossary.terms": "termen in de woordenlijst", + "context.clearAll": "Alles wissen", + "context.saving": "Opslaan...", + "context.save": "Opslaan", + "context.presets.createGlossary": "Woordenlijst maken", + "context.presets.created": "Woordenlijst gemaakt", + "context.presets.createdDesc": "De woordenlijst \\\"{name}\\\" is gemaakt met {count} termen.", + "context.presets.hint": "Klik op een preset om een woordenlijst met domeinspecifieke termen te maken. Beheer je woordenlijsten in het Woordenlijsten-gedeelte.", + "context.glossary.manage": "Woordenlijsten beheren", + "context.saved": "Opgeslagen", + "context.savedDesc": "Je contextinstructies zijn opgeslagen." +} diff --git a/frontend/src/lib/i18n/messages/nl/cookieConsent.json b/frontend/src/lib/i18n/messages/nl/cookieConsent.json new file mode 100644 index 0000000..aeffcd8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/cookieConsent.json @@ -0,0 +1,7 @@ +{ + "cookieConsent.title": "Cookies op Wordly", + "cookieConsent.description": "We gebruiken essentiële cookies zodat de app werkt (sessie, beveiliging, taal). Met uw toestemming gebruiken we ook optionele cookies om verkeer te meten en het product te verbeteren.", + "cookieConsent.acceptAll": "Alles accepteren", + "cookieConsent.essentialOnly": "Alleen essentiële", + "cookieConsent.learnMore": "Meer informatie" +} diff --git a/frontend/src/lib/i18n/messages/nl/dashboard.json b/frontend/src/lib/i18n/messages/nl/dashboard.json new file mode 100644 index 0000000..37749dd --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/dashboard.json @@ -0,0 +1,111 @@ +{ + "dashboard.nav.translate": "Vertalen", + "dashboard.nav.profile": "Mijn profiel", + "dashboard.nav.settings": "Instellingen", + "dashboard.nav.context": "Context", + "dashboard.nav.services": "Diensten", + "dashboard.nav.apiKeys": "API-sleutels", + "dashboard.nav.glossaries": "Woordenlijsten", + "dashboard.header.title": "Dashboard", + "dashboard.header.subtitle": "Beheer uw vertalingen", + "dashboard.header.toggleMenu": "Menu", + "dashboard.header.profileTitle": "Mijn profiel", + "dashboard.sidebar.theme": "Thema", + "dashboard.sidebar.signOut": "Uitloggen", + "dashboard.sidebar.backHome": "Terug naar home", + "dashboard.sidebar.upgradeToPro": "Upgrade naar Pro →", + "dashboard.translate.pageTitle": "Document vertalen", + "dashboard.translate.pageSubtitle": "Importeer een bestand en kies de doeltaal", + "dashboard.translate.errorNotificationTitle": "Fout", + "dashboard.translate.dropzone.uploadAria": "Bestandsdropzone", + "dashboard.translate.dropzone.title": "Sleep uw bestand hierheen", + "dashboard.translate.dropzone.subtitle": "of klik om te selecteren (DOCX, XLSX, PPTX, PDF)", + "dashboard.translate.dropzone.replaceFile": "Bestand vervangen", + "dashboard.translate.language.source": "Brontaal", + "dashboard.translate.language.target": "Doeltaal", + "dashboard.translate.language.loading": "Talen laden…", + "dashboard.translate.language.autoDetect": "Automatisch detecteren", + "dashboard.translate.language.selectPlaceholder": "Selecteren…", + "dashboard.translate.language.loadErrorPrefix": "Fout bij laden van talen", + "dashboard.translate.provider.loading": "Providers laden…", + "dashboard.translate.provider.noneConfigured": "Geen providers geconfigureerd", + "dashboard.translate.provider.modelTitle": "Model", + "dashboard.translate.provider.sectionTitle": "Provider", + "dashboard.translate.provider.llmDivider": "AI · Contextbewust", + "dashboard.translate.provider.llmDividerPro": "AI · Contextbewust (Pro)", + "dashboard.translate.provider.upgrade": "Upgrade naar Pro", + "dashboard.translate.provider.upgradeSuffix": "om AI-vertaling te ontgrendelen", + "dashboard.translate.trust.zeroRetention": "Geen retentie", + "dashboard.translate.trust.deletedAfter": "Bestanden verwijderd na verwerking", + "dashboard.translate.actions.uploading": "Uploaden…", + "dashboard.translate.actions.translate": "Vertalen", + "dashboard.translate.actions.filePrefix": "Bestand: ", + "dashboard.translate.actions.cancel": "Annuleren", + "dashboard.translate.actions.tryAgain": "Opnieuw proberen", + "dashboard.translate.steps.uploading": "Bestand uploaden…", + "dashboard.translate.steps.starting": "Vertaling starten…", + "dashboard.translate.complete.title": "Vertaling voltooid!", + "dashboard.translate.complete.descNamed": "Uw bestand {name} is succesvol vertaald.", + "dashboard.translate.complete.descGeneric": "Uw bestand is succesvol vertaald.", + "dashboard.translate.complete.downloading": "Downloaden…", + "dashboard.translate.complete.download": "Downloaden", + "dashboard.translate.complete.newTranslation": "Nieuwe vertaling", + "dashboard.translate.complete.toastOkTitle": "Succes", + "dashboard.translate.complete.toastOkDesc": "{name} is succesvol gedownload.", + "dashboard.translate.complete.toastFailTitle": "Mislukt", + "dashboard.translate.complete.toastFailDesc": "Vertaling mislukt. Probeer het opnieuw.", + "dashboard.translate.sourceDocument": "Brondocument", + "dashboard.translate.configuration": "Configuratie", + "dashboard.translate.translating": "Vertaling bezig", + "dashboard.translate.liveMonitor": "Live monitor", + "dashboard.translate.summary": "Samenvatting", + "dashboard.translate.engine": "Engine", + "dashboard.translate.confidence": "Vertrouwen", + "dashboard.translate.cancel": "Annuleren", + "dashboard.translate.segments": "Segmenten", + "dashboard.translate.characters": "Tekens", + "dashboard.translate.elapsed": "Verstreken", + "dashboard.translate.segPerMin": "Seg/min", + "dashboard.translate.highQuality": "Hoge kwaliteit", + "dashboard.translate.quality": "Kwaliteit", + "dashboard.translate.completed": "Vertaling voltooid", + "dashboard.translate.replace": "Vervangen", + "dashboard.translate.pdfMode.title": "PDF-vertaalmodus", + "dashboard.translate.pdfMode.preserveLayout": "Indeling behouden", + "dashboard.translate.pdfMode.textOnly": "Alleen tekst", + "dashboard.translate.pdfMode.preserveLayoutDesc": "Behoudt afbeeldingen, tabellen en opmaak. Ideaal voor eenvoudige PDF's.", + "dashboard.translate.pdfMode.textOnlyDesc": "Vertaalt alle tekst perfect. Schone uitvoer, geen opmaakproblemen.", + "dashboard.translate.pipeline.upload": "Uploaden", + "dashboard.translate.pipeline.analyze": "Analyseren", + "dashboard.translate.pipeline.translate": "Vertaling", + "dashboard.translate.pipeline.rebuild": "Reconstrueren", + "dashboard.translate.pipeline.finalize": "Afronden", + "dashboard.translate.progress.processingFallback": "Verwerken…", + "dashboard.translate.progress.connectionLost": "Verbinding verloren. Opnieuw proberen…", + "dashboard.translate.progress.failedTitle": "Vertaling mislukt", + "dashboard.translate.error.unexpected": "Er is een onverwachte fout opgetreden. Probeer het opnieuw.", + "dashboard.translate.error.noResult": "De vertaling leverde geen resultaten op. Controleer of het document tekst bevat en probeer het opnieuw of kies een andere engine.", + "dashboard.translate.error.apiKey": "Ongeldige of ontbrekende API-sleutel. Neem contact op met de beheerder om API-sleutels te configureren.", + "dashboard.translate.error.quota": "Gebruikslimiet bereikt. Probeer het over een paar minuten opnieuw of kies een andere engine.", + "dashboard.translate.error.timeout": "Verbinding met de vertaalservice is verlopen. Controleer uw netwerk en probeer het opnieuw.", + "dashboard.translate.error.sessionExpired": "Sessie verlopen. Klik op Opnieuw proberen om de vertaling te herstarten.", + "dashboard.translate.error.empty": "Het document lijkt leeg of bevat geen vertaalbare tekst (gescande PDF?).", + "dashboard.translate.error.unsupported": "Niet-ondersteund bestandsformaat of beschadigd bestand.", + "dashboard.translate.error.connection": "Verbinding verbroken. Controleer uw netwerk en probeer het opnieuw.", + "dashboard.translate.error.generic": "Vertaling mislukt: {detail}", + "dashboard.translate.error.title": "Vertaling mislukt", + "dashboard.translate.retry": "Probeer opnieuw", + "dashboard.translate.newFile": "Nieuw bestand", + "dashboard.translate.modeAI": "AI-modus", + "dashboard.translate.modeClassic": "Klassieke modus", + "dashboard.translate.glossaryLLMHint": "Woordenlijsten beschikbaar in AI-modus", + "dashboard.translate.submitting": "Bezig met verzenden...", + "dashboard.translate.submit": "Vertaling starten", + "dashboard.translate.noFile": "Upload eerst een bestand", + "dashboard.translate.noTargetLang": "Selecteer een doeltaal", + "dashboard.topbar.interfaceLabel": "Vertaalinterface", + "dashboard.topbar.premiumAccess": "Premium-toegang", + "dashboard.checkoutSyncError": "Fout bij synchroniseren van betaling.", + "dashboard.networkRefresh": "Netwerkfout. Vernieuw de pagina.", + "dashboard.continueToTranslate": "Doorgaan naar vertaling" +} diff --git a/frontend/src/lib/i18n/messages/nl/fileUploader.json b/frontend/src/lib/i18n/messages/nl/fileUploader.json new file mode 100644 index 0000000..83ec657 --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/fileUploader.json @@ -0,0 +1,31 @@ +{ + "fileUploader.uploadDocument": "Document uploaden", + "fileUploader.uploadDesc": "Sleep of klik om een bestand te selecteren (Excel, Word, PowerPoint)", + "fileUploader.dropHere": "Zet uw bestand hier neer…", + "fileUploader.dragAndDrop": "Sleep uw document hierheen", + "fileUploader.orClickBrowse": "of klik om te bladeren", + "fileUploader.preview": "Voorbeeld", + "fileUploader.translationOptions": "Vertaalopties", + "fileUploader.configureSettings": "Vertaalinstellingen configureren", + "fileUploader.targetLanguage": "Doeltaal", + "fileUploader.selectLanguage": "Selecteer taal", + "fileUploader.translationProvider": "Vertaalprovider", + "fileUploader.selectProvider": "Selecteer provider", + "fileUploader.advancedOptions": "Geavanceerde opties", + "fileUploader.translateImages": "Afbeeldingen vertalen", + "fileUploader.translating": "Bezig met vertalen…", + "fileUploader.translateDocument": "Document vertalen", + "fileUploader.processing": "Verwerken…", + "fileUploader.translationError": "Vertaalfout", + "fileUploader.translationComplete": "Vertaling voltooid!", + "fileUploader.translationCompleteDesc": "Uw document is succesvol vertaald met behoud van alle opmaak.", + "fileUploader.download": "Vertaald document downloaden", + "fileUploader.webgpuUnsupported": "WebGPU wordt niet ondersteund in deze browser. Gebruik Chrome 113+ of Edge 113+.", + "fileUploader.webllmNotLoaded": "WebLLM-model niet geladen. Ga naar Instellingen > Vertaaldiensten om een model te laden.", + "fileUploader.extracting": "Teksten uit document extraheren…", + "fileUploader.noTranslatable": "Geen vertaalbare tekst gevonden in document", + "fileUploader.foundTexts": "{count} teksten gevonden om te vertalen", + "fileUploader.translatingItem": "Vertalen {current}/{total}: „{preview}\\\"", + "fileUploader.reconstructing": "Document reconstrueren…", + "fileUploader.translatingLocally": "Lokaal vertalen met WebLLM…" +} diff --git a/frontend/src/lib/i18n/messages/nl/forgotPassword.json b/frontend/src/lib/i18n/messages/nl/forgotPassword.json new file mode 100644 index 0000000..0ac67c8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/forgotPassword.json @@ -0,0 +1,14 @@ +{ + "forgotPassword.enterEmail": "Please enter your email address", + "forgotPassword.error": "An error occurred", + "forgotPassword.title": "Forgot Password", + "forgotPassword.checkEmail": "Check your inbox", + "forgotPassword.subtitle": "Enter your email to receive a reset link", + "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", + "forgotPassword.emailLabel": "Email address", + "forgotPassword.emailPlaceholder": "you@example.com", + "forgotPassword.sending": "Sending...", + "forgotPassword.sendLink": "Send reset link", + "forgotPassword.backToLogin": "Back to login", + "forgotPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/nl/glossaries.json b/frontend/src/lib/i18n/messages/nl/glossaries.json new file mode 100644 index 0000000..2158742 --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/glossaries.json @@ -0,0 +1,189 @@ +{ + "glossaries.yourGlossaries": "Uw woordenlijsten", + "glossaries.title": "Woordenlijsten & Context", + "glossaries.description": "Beheer uw woordenlijsten en contextinstructies voor nauwkeurigere vertalingen.", + "glossaries.createNew": "Nieuwe maken", + "glossaries.empty": "Nog geen woordenlijsten", + "glossaries.emptyDesc": "Maak uw eerste woordenlijst of laad een professionele preset hierboven", + "glossaries.defineTerms": "termen", + "glossaries.aboutTitle": "Over woordenlijsten", + "glossaries.aboutDesc": "Met woordenlijsten kunt u exacte vertalingen definiëren voor specifieke termen. Bij het vertalen worden de termen uit de woordenlijst gebruikt voor consistente en nauwkeurige vertalingen.", + "glossaries.aboutFormat": "Elke term heeft een brontaalwoord en vertalingen in meerdere talen. Selecteer een woordenlijst op de vertaalpagina om deze toe te passen.", + "glossaries.toast.created": "Woordenlijst gemaakt", + "glossaries.toast.createdDesc": "De woordenlijst \\\"{name}\\\" is gemaakt.", + "glossaries.toast.imported": "Woordenlijst geïmporteerd", + "glossaries.toast.importedDesc": "De woordenlijst \\\"{name}\\\" is geïmporteerd.", + "glossaries.toast.updated": "Woordenlijst bijgewerkt", + "glossaries.toast.updatedDesc": "De woordenlijst \\\"{name}\\\" is bijgewerkt.", + "glossaries.toast.deleted": "Woordenlijst verwijderd", + "glossaries.toast.deletedDesc": "De woordenlijst is verwijderd.", + "glossaries.toast.error": "Fout", + "glossaries.toast.errorCreate": "Kan woordenlijst niet maken", + "glossaries.toast.errorImport": "Kan woordenlijst niet importeren", + "glossaries.toast.errorUpdate": "Kan woordenlijst niet bijwerken", + "glossaries.toast.errorDelete": "Kan woordenlijst niet verwijderen", + "glossaries.dialog.title": "Nieuwe woordenlijst", + "glossaries.dialog.description": "Maak een woordenlijst voor uw vertalingen", + "glossaries.dialog.nameLabel": "Naam", + "glossaries.dialog.namePlaceholder": "Mijn woordenlijst", + "glossaries.dialog.tabTemplates": "Sjablonen", + "glossaries.dialog.tabFile": "Bestand", + "glossaries.dialog.tabManual": "Handmatig", + "glossaries.dialog.cancel": "Annuleren", + "glossaries.dialog.creating": "Aanmaken…", + "glossaries.dialog.importing": "Importeren…", + "glossaries.dialog.importBtn": "Importeren", + "glossaries.dialog.selectPrompt": "Selecteren", + "glossaries.dialog.createBtn": "Aanmaken", + "glossaries.dialog.createEmpty": "Leeg aanmaken", + "glossaries.dialog.terms": "termen", + "glossaries.dialog.templatesDesc": "Kies een vooraf gedefinieerd sjabloon", + "glossaries.dialog.templatesEmpty": "Geen sjablonen beschikbaar", + "glossaries.dialog.dropTitle": "Sleep een CSV-bestand hierheen", + "glossaries.dialog.dropOr": "of", + "glossaries.dialog.dropFormats": "CSV, TSV, TXT", + "glossaries.termEditor.addTerm": "Term toevoegen", + "glossaries.termEditor.maxReached": "Maximum van {max} termen per glossarium bereikt.", + "glossaries.dialog.formatTitle": "Indeling", + "glossaries.dialog.formatDesc": "bron,doel (één per regel)", + "glossaries.dialog.formatNote": "Eerste regel overgeslagen als koptekst wordt gedetecteerd", + "glossaries.dialog.errorFormat": "Niet-ondersteunde indeling", + "glossaries.dialog.errorSize": "Bestand te groot", + "glossaries.dialog.errorEmpty": "Leeg bestand", + "glossaries.dialog.errorRead": "Leesfout", + "glossaries.dialog.parsing": "Verwerken…", + "glossaries.dialog.termsImported": "termen geïmporteerd", + "glossaries.dialog.changeFile": "Bestand wijzigen", + "glossaries.dialog.retry": "Opnieuw proberen", + "glossaries.edit.title": "Modifier le glossaire", + "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", + "glossaries.edit.nameLabel": "Nom du glossaire", + "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", + "glossaries.edit.sourceLang": "Langue source", + "glossaries.edit.targetLang": "Langue cible", + "glossaries.edit.termsLabel": "Termes ({count} valides)", + "glossaries.edit.exportCsv": "Exporter CSV", + "glossaries.edit.importCsv": "Importer CSV", + "glossaries.edit.cancel": "Annuler", + "glossaries.edit.saving": "Enregistrement...", + "glossaries.edit.saveChanges": "Enregistrer les modifications", + "glossaries.edit.importFailedTitle": "Échec de l'importation", + "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", + "glossaries.edit.importSuccessTitle": "Importation réussie", + "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", + "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", + "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", + "glossaries.delete.title": "Supprimer le glossaire", + "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", + "glossaries.delete.warning": "Cette action est irréversible", + "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", + "glossaries.delete.cancel": "Annuler", + "glossaries.delete.deleting": "Suppression...", + "glossaries.delete.deleteBtn": "Supprimer", + "glossaries.upgrade.title": "Glossaires", + "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", + "glossaries.upgrade.feature1": "Créez plusieurs glossaires", + "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", + "glossaries.upgrade.feature3": "Importez/exportez via CSV", + "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", + "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", + "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", + "glossaries.upgrade.proLabel": "Pro", + "glossaries.upgrade.upgradeBtn": "Passer à Pro", + "glossaries.loading": "Chargement...", + "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", + "glossaries.howItWorks.step1Title": "Configurez ici", + "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", + "glossaries.howItWorks.step2Title": "Activez dans Traduire", + "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", + "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", + "glossaries.howItWorks.goToTranslate": "Aller à Traduire", + "glossaries.status.unsaved": "Non enregistré", + "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", + "glossaries.status.inactive": "Inactif", + "glossaries.instructions.whatForBold": "À quoi ça sert ?", + "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", + "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", + "glossaries.instructions.charCount": "{count} caractères", + "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", + "glossaries.instructions.clearAll": "Tout effacer", + "glossaries.instructions.saving": "Enregistrement…", + "glossaries.instructions.saved": "Enregistré", + "glossaries.presets.whatForBold": "À quoi ça sert ?", + "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", + "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", + "glossaries.presets.creating": "Création…", + "glossaries.presets.alreadyImported": "Déjà importé", + "glossaries.presets.it.title": "IT / Logiciel", + "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", + "glossaries.presets.legal.title": "Juridique / Contrats", + "glossaries.presets.legal.desc": "Droit des affaires, contentieux", + "glossaries.presets.medical.title": "Médical / Santé", + "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", + "glossaries.presets.finance.title": "Finance / Comptabilité", + "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", + "glossaries.presets.marketing.title": "Marketing / Publicité", + "glossaries.presets.marketing.desc": "Digital, branding, analytics", + "glossaries.presets.hr.title": "RH / Ressources Humaines", + "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", + "glossaries.presets.scientific.title": "Scientifique / Recherche", + "glossaries.presets.scientific.desc": "Publications, thèses, articles", + "glossaries.presets.ecommerce.title": "E-commerce / Vente", + "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", + "glossaries.grid.title": "Vos", + "glossaries.grid.titleHighlight": "glossaires", + "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", + "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", + "glossaries.grid.activeTranslation": "Traduction active :", + "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", + "glossaries.badge.compatible": "Compatible", + "glossaries.badge.otherTarget": "Autre cible", + "glossaries.card.editTerms": "Modifier les termes", + "glossaries.card.created": "Aangemaakt", + "glossaries.card.term": "term", + "glossaries.card.delete": "Supprimer", + "glossaries.grid.searchPlaceholder": "Search a glossary…", + "glossaries.grid.noResults": "No results for this search.", + "glossaries.detail.backToList": "Back to glossaries", + "glossaries.detail.save": "Save", + "glossaries.detail.savedTitle": "Saved", + "glossaries.detail.savedDesc": "The glossary has been updated.", + "glossaries.detail.settingsTitle": "Settings", + "glossaries.detail.sourceLang": "Source language", + "glossaries.detail.targetLang": "Target language", + "glossaries.detail.termsTitle": "Terms", + "glossaries.detail.terms": "terms", + "glossaries.detail.searchTerms": "Filter…", + "glossaries.detail.noTerms": "No terms yet.", + "glossaries.detail.addFirstTerm": "Add the first term", + "glossaries.detail.addTerm": "Add a term", + "glossaries.detail.maxReached": "Maximum limit reached", + "glossaries.detail.source": "Source", + "glossaries.detail.target": "Target", + "glossaries.detail.sourcePlaceholder": "source term", + "glossaries.detail.targetPlaceholder": "target term", + "glossaries.detail.csvTitle": "CSV", + "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", + "glossaries.detail.export": "Export", + "glossaries.detail.import": "Import", + "glossaries.detail.dangerTitle": "Danger zone", + "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", + "glossaries.detail.deleteGlossary": "Delete this glossary", + "glossaries.detail.confirmDelete": "Confirm deletion?", + "glossaries.detail.confirm": "Confirm", + "glossaries.detail.cancel": "Cancel", + "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", + "glossaries.detail.sourceLocked": "fixed", + "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", + "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", + "glossaries.detail.notFoundTitle": "Glossary not found", + "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", + "glossaries.detail.maxTermsTitle": "Limit reached", + "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", + "glossaries.detail.importEmptyTitle": "Empty file", + "glossaries.detail.importEmptyDesc": "No terms detected in this file.", + "glossaries.detail.importedTitle": "Imported", + "glossaries.detail.importedDesc": "{count} terms imported.", + "glossaries.detail.importErrorTitle": "Read error", + "glossaries.detail.importErrorDesc": "Unable to read the file." +} diff --git a/frontend/src/lib/i18n/messages/nl/index.ts b/frontend/src/lib/i18n/messages/nl/index.ts new file mode 100644 index 0000000..43e4f9e --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/index.ts @@ -0,0 +1,60 @@ +// Auto-generated by scripts/generate_i18n_index.py +// Merges all namespace JSON files for locale "nl". + +import admin from "./admin.json"; +import apiKeys from "./apiKeys.json"; +import auth from "./auth.json"; +import checkout from "./checkout.json"; +import common from "./common.json"; +import context from "./context.json"; +import cookieConsent from "./cookieConsent.json"; +import dashboard from "./dashboard.json"; +import fileUploader from "./fileUploader.json"; +import forgotPassword from "./forgotPassword.json"; +import glossaries from "./glossaries.json"; +import landing from "./landing.json"; +import langSelector from "./langSelector.json"; +import layout from "./layout.json"; +import login from "./login.json"; +import memento from "./memento.json"; +import pricing from "./pricing.json"; +import profile from "./profile.json"; +import providerSelector from "./providerSelector.json"; +import providerTheme from "./providerTheme.json"; +import register from "./register.json"; +import resetPassword from "./resetPassword.json"; +import services from "./services.json"; +import settings from "./settings.json"; +import translate from "./translate.json"; +import translateComplete from "./translateComplete.json"; + +const messages: Record = { + ...admin, + ...apiKeys, + ...auth, + ...checkout, + ...common, + ...context, + ...cookieConsent, + ...dashboard, + ...fileUploader, + ...forgotPassword, + ...glossaries, + ...landing, + ...langSelector, + ...layout, + ...login, + ...memento, + ...pricing, + ...profile, + ...providerSelector, + ...providerTheme, + ...register, + ...resetPassword, + ...services, + ...settings, + ...translate, + ...translateComplete, +}; + +export default messages; diff --git a/frontend/src/lib/i18n/messages/nl/landing.json b/frontend/src/lib/i18n/messages/nl/landing.json new file mode 100644 index 0000000..a985e4c --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/landing.json @@ -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" +} diff --git a/frontend/src/lib/i18n/messages/nl/langSelector.json b/frontend/src/lib/i18n/messages/nl/langSelector.json new file mode 100644 index 0000000..3b3340d --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/langSelector.json @@ -0,0 +1,7 @@ +{ + "langSelector.search": "Zoeken…", + "langSelector.noResults": "Geen resultaten", + "langSelector.source": "Bron", + "langSelector.target": "Doel", + "langSelector.swap": "Wisselen" +} diff --git a/frontend/src/lib/i18n/messages/nl/layout.json b/frontend/src/lib/i18n/messages/nl/layout.json new file mode 100644 index 0000000..ee5dddd --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/layout.json @@ -0,0 +1,5 @@ +{ + "layout.nav.apiAccess": "API-toegang", + "layout.footer.terms": "Voorwaarden", + "layout.footer.privacy": "Privacy" +} diff --git a/frontend/src/lib/i18n/messages/nl/login.json b/frontend/src/lib/i18n/messages/nl/login.json new file mode 100644 index 0000000..ec156a2 --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/login.json @@ -0,0 +1,18 @@ +{ + "login.errorTitle": "Login Error", + "login.welcomeBack": "Welcome back", + "login.signInToContinue": "Sign in to continue translating", + "login.email": "Email", + "login.emailPlaceholder": "you@example.com", + "login.password": "Password", + "login.forgotPassword": "Forgot password?", + "login.passwordPlaceholder": "••••••••", + "login.signingIn": "Signing in...", + "login.signIn": "Sign In", + "login.noAccount": "Don't have an account?", + "login.signUpFree": "Sign up for free", + "login.orContinueWith": "of ga verder met e-mail", + "login.google.connecting": "Verbinden…", + "login.google.errorGeneric": "Er is iets misgegaan met Google-aanmelding.", + "login.google.errorFailed": "Google-aanmelding mislukt. Probeer het opnieuw." +} diff --git a/frontend/src/lib/i18n/messages/nl/memento.json b/frontend/src/lib/i18n/messages/nl/memento.json new file mode 100644 index 0000000..80ca1eb --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/memento.json @@ -0,0 +1,6 @@ +{ + "memento.title": "Ontdek Momento", + "memento.slogan": "Momento is meer dan alleen een notitie-app. Het is een intelligent ecosysteem dat uw ideeën in realtime verbindt, analyseert en verder ontwikkelt met 6 AI-agents en geavanceerde semantische zoekfuncties.", + "memento.ctaFree": "Gratis beginnen", + "memento.ctaMore": "Meer informatie" +} diff --git a/frontend/src/lib/i18n/messages/nl/pricing.json b/frontend/src/lib/i18n/messages/nl/pricing.json new file mode 100644 index 0000000..6cbfa1a --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/pricing.json @@ -0,0 +1,151 @@ +{ + "pricing.nav.back": "Terug", + "pricing.nav.home": "Home", + "pricing.nav.mySubscription": "Mijn abonnement", + "pricing.header.badge": "AI-modellen bijgewerkt — maart 2026", + "pricing.header.title": "Een abonnement voor elke behoefte", + "pricing.header.subtitle": "Vertaal uw Word-, Excel- en PowerPoint-documenten met behoud van de originele opmaak. Geen API-sleutel vereist.", + "pricing.billing.monthly": "Maandelijks", + "pricing.billing.yearly": "Jaarlijks", + "pricing.plans.free.name": "Gratis", + "pricing.plans.starter.name": "Starter", + "pricing.plans.pro.name": "Pro", + "pricing.plans.business.name": "Business", + "pricing.plans.enterprise.name": "Enterprise", + "pricing.plans.free.description": "Perfect om de app te ontdekken", + "pricing.plans.starter.description": "Voor particulieren en kleine projecten", + "pricing.plans.pro.description": "Voor professionals en groeiende teams", + "pricing.plans.business.description": "Voor teams en organisaties", + "pricing.plans.enterprise.description": "Maatwerkoplossingen voor grote organisaties", + "pricing.plans.pro.highlight": "Meest gekozen", + "pricing.plans.pro.badge": "POPULAIR", + "pricing.plans.enterprise.badge": "OP AANVRAAG", + "pricing.plans.free.feat1": "5 documenten / maand", + "pricing.plans.free.feat2": "Tot 15 pagina's per document", + "pricing.plans.free.feat3": "Google Vertalen inbegrepen", + "pricing.plans.free.feat4": "Alle talen (130+)", + "pricing.plans.free.feat5": "Communitysupport", + "pricing.plans.starter.feat1": "50 documenten / maand", + "pricing.plans.starter.feat2": "Tot 50 pagina's per document", + "pricing.plans.starter.feat3": "Google Vertalen + DeepL", + "pricing.plans.starter.feat4": "Bestanden tot 10 MB", + "pricing.plans.starter.feat5": "E-mailsupport", + "pricing.plans.starter.feat6": "30 dagen geschiedenis", + "pricing.plans.pro.feat1": "200 documenten / maand", + "pricing.plans.pro.feat2": "Tot 200 pagina's per document", + "pricing.plans.pro.feat3": "Essentiële IA-vertaling", + "pricing.plans.pro.feat4": "Google Vertalen + DeepL", + "pricing.plans.pro.feat5": "Bestanden tot 25 MB", + "pricing.plans.pro.feat6": "Aangepaste woordenlijsten", + "pricing.plans.pro.feat7": "Prioriteitssupport", + "pricing.plans.pro.feat8": "90 dagen geschiedenis", + "pricing.plans.business.feat1": "1 000 documenten / maand", + "pricing.plans.business.feat2": "Tot 500 pagina's per document", + "pricing.plans.business.feat3": "Basis- + Premium-AI (Claude Haiku)", + "pricing.plans.business.feat4": "Alle vertaalproviders", + "pricing.plans.business.feat5": "Bestanden tot 50 MB", + "pricing.plans.business.feat6": "API-toegang (10 000 aanroepen/maand)", + "pricing.plans.business.feat7": "Meldingswebhooks", + "pricing.plans.business.feat8": "Dedicated support", + "pricing.plans.business.feat9": "1 jaar geschiedenis", + "pricing.plans.business.feat10": "Geavanceerde analyses", + "pricing.plans.enterprise.feat1": "Onbeperkte documenten", + "pricing.plans.enterprise.feat2": "Alle AI-modellen (GPT-5, Claude Opus 4.6…)", + "pricing.plans.enterprise.feat3": "On-premise of dedicated cloud", + "pricing.plans.enterprise.feat4": "99,9 % SLA gegarandeerd", + "pricing.plans.enterprise.feat5": "24/7 dedicated support", + "pricing.plans.enterprise.feat6": "White-label", + "pricing.plans.enterprise.feat7": "Onbeperkte teams", + "pricing.plans.enterprise.feat8": "Maatwerkintegraties", + "pricing.card.onRequest": "Op aanvraag", + "pricing.card.free": "Gratis", + "pricing.card.perMonth": "/maand", + "pricing.card.billedYearly": "Gefactureerd {price} € / jaar", + "pricing.card.documents": "Documenten", + "pricing.card.pagesMax": "Max. pagina's", + "pricing.card.aiTranslation": "AI-vertaling", + "pricing.card.unlimited": "Onbeperkt", + "pricing.card.perMonthStat": "/ maand", + "pricing.card.perDoc": "p / doc", + "pricing.card.aiEssential": "Basis", + "pricing.card.aiEssentialPremium": "Basis + Premium", + "pricing.card.aiCustom": "Maatwerk", + "pricing.card.myPlan": "Mijn abonnement", + "pricing.card.managePlan": "Abonnement beheren", + "pricing.card.startFree": "Gratis starten", + "pricing.card.contactUs": "Neem contact op", + "pricing.card.choosePlan": "Dit abonnement kiezen", + "pricing.card.processing": "Verwerken…", + "pricing.comparison.title": "Gedetailleerde vergelijking", + "pricing.comparison.subtitle": "Alles wat in elk abonnement is inbegrepen", + "pricing.comparison.feature": "Functie", + "pricing.comparison.docsPerMonth": "Documenten / maand", + "pricing.comparison.pagesMaxPerDoc": "Max. pagina's / document", + "pricing.comparison.maxFileSize": "Max. bestandsgrootte", + "pricing.comparison.googleTranslation": "Google Vertalen", + "pricing.comparison.deepl": "DeepL", + "pricing.comparison.aiEssential": "AI-basisvertaling", + "pricing.comparison.aiPremium": "AI-premiumvertaling", + "pricing.comparison.apiAccess": "API-toegang", + "pricing.comparison.priorityProcessing": "Prioriteitsverwerking", + "pricing.comparison.support": "Support", + "pricing.comparison.support.community": "Community", + "pricing.comparison.support.email": "E-mail", + "pricing.comparison.support.priority": "Prioriteit", + "pricing.comparison.support.dedicated": "Dedicated", + "pricing.comparison.mb": "MB", + "pricing.credits.title": "Extra tegoeden", + "pricing.credits.subtitle": "Meer nodig? Koop tegoeden per stuk, zonder abonnement.", + "pricing.credits.perPage": "1 tegoed = 1 vertaalde pagina.", + "pricing.credits.bestValue": "Beste waarde", + "pricing.credits.unit": "tegoeden", + "pricing.credits.centsPerCredit": "ct / tegoed", + "pricing.credits.buy": "Kopen", + "pricing.trust.encryption.title": "End-to-end-versleuteling", + "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 at-rest", + "pricing.trust.languages.title": "130+ talen", + "pricing.trust.languages.sub": "Inclusief Arabisch, Perzisch, Hebreeuws (RTL)", + "pricing.trust.parallel.title": "Parallelle verwerking", + "pricing.trust.parallel.sub": "Ultrasnelle multi-threaded AI", + "pricing.trust.availability.title": "24/7 beschikbaar", + "pricing.trust.availability.sub": "99,9 % gegarandeerde beschikbaarheid", + "pricing.aiModels.title": "Onze AI-modellen — maart 2026", + "pricing.aiModels.essential.title": "AI-basisvertaling", + "pricing.aiModels.essential.plan": "Pro-abonnement", + "pricing.aiModels.essential.descPrefix": "Gebaseerd op", + "pricing.aiModels.essential.descSuffix": "— het meest kostenefficiënte AI-model van 2026. Kwaliteit vergelijkbaar met frontier-modellen voor een fractie van de kosten.", + "pricing.aiModels.essential.modelName": "ons Essential AI-model", + "pricing.aiModels.essential.context": "163K tokens context", + "pricing.aiModels.essential.value": "Uitstekende prijs-kwaliteitverhouding", + "pricing.aiModels.premium.title": "AI-premiumvertaling", + "pricing.aiModels.premium.plan": "Business-abonnement", + "pricing.aiModels.premium.descPrefix": "Gebaseerd op", + "pricing.aiModels.premium.descSuffix": "van Anthropic — nauwkeurig bij juridische, medische en complexe technische documenten.", + "pricing.aiModels.premium.context": "200K tokens context", + "pricing.aiModels.premium.precision": "Beste nauwkeurigheid", + "pricing.faq.title": "Veelgestelde vragen", + "pricing.faq.q1": "Kan ik op elk moment van abonnement wisselen?", + "pricing.faq.a1": "Ja. Upgraden gebeurt direct en naar rato. Downgraden gaat in aan het einde van de lopende periode.", + "pricing.faq.q2": "Wat is «AI-basisvertaling»?", + "pricing.faq.a2": "Het is onze IA-engine. Hij begrijpt de context van uw documenten, behoudt de lay-out en behandelt technische termen veel beter dan klassieke vertaling.", + "pricing.faq.q3": "Wat is het verschil tussen Basis- en Premium-AI?", + "pricing.faq.a3": "Essential IA gebruikt een geoptimaliseerd model (uitstekende prijs-kwaliteitverhouding). Premium IA gebruikt Claude 3.5 Haiku van Anthropic, nauwkeuriger bij juridische, medische en complexe technische documenten.", + "pricing.faq.q4": "Worden mijn documenten bewaard na vertaling?", + "pricing.faq.a4": "Vertaalde bestanden zijn beschikbaar volgens uw abonnement (30 dagen Starter, 90 dagen Pro, 1 jaar Business). Ze zijn versleuteld at-rest en in transit.", + "pricing.faq.q5": "Wat gebeurt er als ik mijn maandelijkse quotum overschrijd?", + "pricing.faq.a5": "U kunt extra tegoeden per stuk kopen of uw abonnement upgraden. U wordt op de hoogte gesteld bij 80 % gebruik.", + "pricing.faq.q6": "Is er een gratis proefperiode voor betaalde abonnementen?", + "pricing.faq.a6": "Het Gratis abonnement is permanent en vereist geen creditcard. Voor Pro en Business kunt u ons contacteren voor een proefperiode van 14 dagen.", + "pricing.faq.q7": "Welke bestandsformaten worden ondersteund?", + "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx) en binnenkort PDF. Alle abonnementen ondersteunen dezelfde formaten.", + "pricing.cta.title": "Klaar om te beginnen?", + "pricing.cta.subtitle": "Start gratis, zonder creditcard. Upgrade wanneer u wilt.", + "pricing.cta.createAccount": "Gratis account aanmaken", + "pricing.cta.login": "Inloggen", + "pricing.toast.demo": "Demomodus — Stripe is nog niet geconfigureerd. In productie zou u worden doorgestuurd naar betaling om het {planId}-abonnement te activeren.", + "pricing.toast.networkError": "Netwerkfout. Probeer het opnieuw.", + "pricing.toast.paymentError": "Fout bij aanmaken van de betaling.", + "pricing.dashboard": "Dashboard", + "pricing.okSymbol": "✓", + "pricing.errSymbol": "✕" +} diff --git a/frontend/src/lib/i18n/messages/nl/profile.json b/frontend/src/lib/i18n/messages/nl/profile.json new file mode 100644 index 0000000..7f5cd8f --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/profile.json @@ -0,0 +1,58 @@ +{ + "profile.header.title": "Mijn profiel", + "profile.header.subtitle": "Beheer je account en voorkeuren.", + "profile.tabs.account": "Account", + "profile.tabs.subscription": "Abonnement", + "profile.tabs.preferences": "Voorkeuren", + "profile.account.user": "Gebruiker", + "profile.account.memberSince": "Lid sinds", + "profile.plan.label": "Abonnement", + "profile.plan.free": "Free", + "profile.plan.starter": "Starter", + "profile.plan.pro": "Pro", + "profile.plan.business": "Business", + "profile.plan.enterprise": "Enterprise", + "profile.plan.pricePerMonth": "{price} €/maand", + "profile.subscription.canceling": "Wordt geannuleerd", + "profile.subscription.active": "Actief", + "profile.subscription.unknown": "Onbekend", + "profile.subscription.accessUntil": "Toegang tot", + "profile.subscription.renewalOn": "Verlenging op", + "profile.subscription.upgradePlan": "Upgrade naar een betaald abonnement", + "profile.subscription.changePlan": "Abonnement wijzigen", + "profile.subscription.manageBilling": "Facturatie beheren", + "profile.subscription.billingUnavailable": "Facturatieportaal niet beschikbaar.", + "profile.subscription.billingError": "Fout bij toegang tot facturatieportaal.", + "profile.subscription.cancelSuccess": "Abonnement geannuleerd. Je behoudt toegang tot het einde van de periode.", + "profile.subscription.cancelError": "Fout bij annulering.", + "profile.subscription.networkError": "Netwerkfout.", + "profile.usage.title": "Gebruik deze maand", + "profile.usage.resetOn": "Reset op", + "profile.usage.documents": "Documenten", + "profile.usage.pages": "Pagina's", + "profile.usage.extraCredits": "extra tegoed", + "profile.usage.extraCreditsPlural": "extra tegoeden", + "profile.usage.quotaReached": "Quota bereikt", + "profile.usage.quotaReachedDesc": "Upgrade naar een hoger abonnement om door te gaan.", + "profile.usage.unlockMore": "Ontgrendel meer vertalingen met een betaald abonnement.", + "profile.usage.viewPlans": "Abonnementen bekijken", + "profile.usage.includedInPlan": "Inbegrepen in je abonnement", + "profile.danger.title": "Gevaarzone", + "profile.danger.description": "Annulering wordt van kracht aan het einde van je huidige periode. Je behoudt toegang tot die datum.", + "profile.danger.confirm": "Weet je het zeker? Deze actie kan niet ongedaan worden gemaakt.", + "profile.danger.confirmCancel": "Annulering bevestigen", + "profile.danger.cancelSubscription": "Mijn abonnement annuleren", + "profile.danger.keep": "Nee, behouden", + "profile.prefs.interfaceLang": "Interfacetaal", + "profile.prefs.interfaceLangDesc": "De taal wordt automatisch gedetecteerd op basis van je browser. Je kunt deze handmatig wijzigen.", + "profile.prefs.defaultTargetLang": "Standaarddoeltaal", + "profile.prefs.selectLanguage": "Selecteer een taal", + "profile.prefs.defaultTargetLangDesc": "Deze taal wordt vooraf geselecteerd voor je vertalingen.", + "profile.prefs.save": "Opslaan", + "profile.prefs.theme": "Thema", + "profile.prefs.themeDesc": "Kies het uiterlijk van de interface", + "profile.prefs.cache": "Cache", + "profile.prefs.cacheDesc": "Het wissen van de lokale cache kan sommige weergaveproblemen oplossen.", + "profile.prefs.clearing": "Wissen...", + "profile.prefs.clearCache": "Cache wissen" +} diff --git a/frontend/src/lib/i18n/messages/nl/providerSelector.json b/frontend/src/lib/i18n/messages/nl/providerSelector.json new file mode 100644 index 0000000..6f6fbea --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/providerSelector.json @@ -0,0 +1,7 @@ +{ + "providerSelector.noClassic": "Geen standaard vertaler beschikbaar.", + "providerSelector.noLlm": "Geen AI-model geconfigureerd.", + "providerSelector.costOne": "Kosten: 1 credit per pagina", + "providerSelector.costFive": "Kosten: 5 credits per pagina (Premium-factor)", + "providerSelector.unlockContextual": "Premium contextuele vertaling voor uw volledige documenten ontgrendelen." +} diff --git a/frontend/src/lib/i18n/messages/nl/providerTheme.json b/frontend/src/lib/i18n/messages/nl/providerTheme.json new file mode 100644 index 0000000..84dab24 --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/providerTheme.json @@ -0,0 +1,29 @@ +{ + "providerTheme.deepseek.badge": "Essentieel", + "providerTheme.deepseek.subBadge": "Technisch & zuinig", + "providerTheme.deepseek.desc": "Ultraprecieze en zuinige vertaling, ideaal voor technische documenten en code.", + "providerTheme.openai.badge": "Premium", + "providerTheme.openai.subBadge": "Hoge getrouwheid", + "providerTheme.openai.desc": "De wereldwijde AI-standaard. Maximale tekstconsistentie en strikte stijlrespect.", + "providerTheme.minimax.badge": "Geavanceerd", + "providerTheme.minimax.subBadge": "Prestaties", + "providerTheme.minimax.desc": "Ongelofelijke uitvoersnelheid en uitstekend begrip van complexe structuren.", + "providerTheme.openrouter.badge": "Express", + "providerTheme.openrouter.subBadge": "Multi-model", + "providerTheme.openrouter.desc": "Uniforme toegang tot de beste open-source modellen, geoptimaliseerd voor vertaling.", + "providerTheme.openrouter_premium.badge": "Ultra", + "providerTheme.openrouter_premium.subBadge": "Maximale context", + "providerTheme.openrouter_premium.desc": "Ondersteund door state-of-the-art modellen (GPT-4o, Claude Sonnet 4.6) voor lange documenten.", + "providerTheme.zai.badge": "Gespecialiseerd", + "providerTheme.zai.subBadge": "Financiën & Recht", + "providerTheme.zai.desc": "Model afgestemd op veeleisende bedrijfsterminologieën (juridisch, financieel).", + "providerTheme.default.badge": "Modern", + "providerTheme.default.subBadge": "AI-redenering", + "providerTheme.default.desc": "Grote taalmodel (LLM) vertaling met geavanceerde semantische analyse.", + "providerTheme.classic.google.label": "Google Vertalen", + "providerTheme.classic.google.desc": "Ultrasnelle vertaling voor meer dan 130 talen. Aanbevolen voor algemene stromen.", + "providerTheme.classic.deepl.label": "DeepL Pro", + "providerTheme.classic.deepl.desc": "Hoge precisie vertaling, bekend om vloeibaarheid en natuurlijke formuleringen.", + "providerTheme.classic.google_cloud.label": "Google Cloud API", + "providerTheme.classic.google_cloud.desc": "Professionele cloud-engine geoptimaliseerd voor het verwerken van grote documentvolumes." +} diff --git a/frontend/src/lib/i18n/messages/nl/register.json b/frontend/src/lib/i18n/messages/nl/register.json new file mode 100644 index 0000000..dd5d9f9 --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/register.json @@ -0,0 +1,29 @@ +{ + "register.title": "Account aanmaken", + "register.subtitle": "Begin gratis met vertalen", + "register.error.failed": "Registratie mislukt", + "register.name.label": "Naam", + "register.name.placeholder": "Uw naam", + "register.name.error": "De naam moet minimaal 2 tekens bevatten", + "register.email.label": "E-mailadres", + "register.email.placeholder": "u@voorbeeld.nl", + "register.email.error": "Ongeldig e-mailadres", + "register.password.label": "Wachtwoord", + "register.password.error": "Het wachtwoord moet minimaal 8 tekens bevatten, met een hoofdletter, een kleine letter en een cijfer", + "register.password.show": "Wachtwoord tonen", + "register.password.hide": "Wachtwoord verbergen", + "register.password.strengthLabel": "Sterkte:", + "register.password.strength.weak": "Zwak", + "register.password.strength.medium": "Gemiddeld", + "register.password.strength.strong": "Sterk", + "register.confirmPassword.label": "Wachtwoord bevestigen", + "register.confirmPassword.error": "Wachtwoorden komen niet overeen", + "register.confirmPassword.show": "Tonen", + "register.confirmPassword.hide": "Verbergen", + "register.submit.creating": "Account wordt aangemaakt...", + "register.submit.create": "Mijn account aanmaken", + "register.hasAccount": "Al een account?", + "register.login": "Inloggen", + "register.terms.prefix": "Door een account aan te maken, accepteert u onze", + "register.terms.link": "gebruiksvoorwaarden" +} diff --git a/frontend/src/lib/i18n/messages/nl/resetPassword.json b/frontend/src/lib/i18n/messages/nl/resetPassword.json new file mode 100644 index 0000000..680714f --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/resetPassword.json @@ -0,0 +1,22 @@ +{ + "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", + "resetPassword.passwordMismatch": "Passwords do not match", + "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", + "resetPassword.error": "An error occurred", + "resetPassword.invalidLink": "Invalid link", + "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", + "resetPassword.requestNewLink": "Request new link", + "resetPassword.successTitle": "Password reset", + "resetPassword.newPasswordTitle": "New password", + "resetPassword.successSubtitle": "You will be redirected to login", + "resetPassword.subtitle": "Set your new password", + "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", + "resetPassword.newPassword": "New password", + "resetPassword.showPassword": "Show password", + "resetPassword.hidePassword": "Hide password", + "resetPassword.confirmPassword": "Confirm password", + "resetPassword.resetting": "Resetting...", + "resetPassword.resetPassword": "Reset password", + "resetPassword.backToLogin": "Back to login", + "resetPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/nl/services.json b/frontend/src/lib/i18n/messages/nl/services.json new file mode 100644 index 0000000..cc42932 --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/services.json @@ -0,0 +1,14 @@ +{ + "services.title": "Vertaalaanbieders", + "services.subtitle": "Aanbieders worden geconfigureerd door de beheerder. Je kunt zien welke momenteel beschikbaar zijn voor je account.", + "services.loading": "Aanbieders laden...", + "services.noProviders": "Er zijn momenteel geen aanbieders geconfigureerd. Neem contact op met je beheerder.", + "services.classic": "Klassieke vertaling", + "services.llmPro": "LLM · Contextbewust (Pro)", + "services.available": "Beschikbaar", + "services.model": "Model", + "services.adminOnly.title": "Aanbiederconfiguratie is alleen voor beheerders", + "services.adminOnly.desc": "API-sleutels, modelselectie en aanbiederactivering worden uitsluitend beheerd door de beheerder in het adminpaneel. Je hoeft nooit een API-sleutel in te voeren.", + "services.fallback.google.label": "Google Vertalen", + "services.fallback.google.desc": "Snelle vertaling, 130+ talen" +} diff --git a/frontend/src/lib/i18n/messages/nl/settings.json b/frontend/src/lib/i18n/messages/nl/settings.json new file mode 100644 index 0000000..60ee2ab --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/settings.json @@ -0,0 +1,20 @@ +{ + "settings.title": "Instellingen", + "settings.subtitle": "Algemene toepassingsconfiguratie", + "settings.formats.title": "Ondersteunde formaten", + "settings.formats.subtitle": "Documenttypen die je kunt vertalen", + "settings.formats.formulas": "Formules", + "settings.formats.styles": "Stijlen", + "settings.formats.images": "Afbeeldingen", + "settings.formats.headers": "Koppen", + "settings.formats.tables": "Tabellen", + "settings.formats.slides": "Dia's", + "settings.formats.notes": "Notities", + "settings.cache.title": "Cache", + "settings.cache.desc": "Het wissen van de lokale cache kan sommige weergaveproblemen oplossen.", + "settings.cache.clearing": "Wissen...", + "settings.cache.clear": "Cache wissen", + "settings.formats.excel.name": "Excel", + "settings.formats.word.name": "Word", + "settings.formats.powerpoint.name": "PowerPoint" +} diff --git a/frontend/src/lib/i18n/messages/nl/translate.json b/frontend/src/lib/i18n/messages/nl/translate.json new file mode 100644 index 0000000..ddae2b7 --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/translate.json @@ -0,0 +1,92 @@ +{ + "translate.mode.label": "Mode de traduction", + "translate.mode.classic": "Classique", + "translate.mode.classicDesc": "Rapide", + "translate.mode.proLlm": "Pro LLM", + "translate.mode.proLlmDesc": "Contextuel", + "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", + "translate.mode.upgradeLink": "Passer à Pro", + "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", + "translate.glossary.title": "Woordenlijst", + "translate.glossary.select": "Woordenlijst selecteren", + "translate.glossary.none": "Geen", + "translate.glossary.terms": "termen", + "translate.glossary.proOnly": "Upgrade naar Pro voor woordenlijsten", + "translate.glossary.myGlossaries": "Mijn woordenlijsten", + "translate.glossary.fromTemplate": "Van sjabloon maken", + "translate.glossary.noGlossaryForPair": "Geen woordenlijst voor", + "translate.glossary.noGlossaries": "Geen woordenlijsten", + "translate.glossary.loading": "Laden...", + "translate.glossary.classicMode": "Neutrale motor zonder woordenlijst (alleen AI)", + "translate.glossary.selectPlaceholder": "Woordenlijst selecteren...", + "translate.glossary.multilingual": "MEERTALIG", + "translate.glossary.noGlossaryAvailable": "Geen woordenlijst beschikbaar", + "translate.glossary.filterByLang": "Filteren op taal", + "translate.glossary.active": "Actief", + "translate.glossary.inactive": "Inactief", + "translate.glossary.availableTemplates": "Beschikbare sjablonen", + "translate.glossary.importing": "Bezig met importeren...", + "translate.glossary.imported": "(Geïmporteerd)", + "translate.glossary.noGlossaryForSource": "Geen woordenlijst of sjabloon voor brontaal", + "translate.glossary.createGlossary": "Woordenlijst maken", + "translate.glossary.showAll": "Alle woordenlijsten tonen", + "translate.glossary.activePreview": "Voorbeeld van actieve overeenkomsten:", + "translate.glossary.total": "totaal", + "translate.glossary.moreTerms": "meer termen", + "translate.glossary.noTerms": "Geen termen in deze woordenlijst.", + "translate.glossary.sourceTerm": "Bronterm", + "translate.glossary.translation": "Vertaling", + "translate.glossary.addTerm": "Term toevoegen", + "translate.glossary.disabledMode": "Neutrale motor zonder toegepaste woordenlijst", + "translate.glossary.addTermError": "Fout bij toevoegen van term", + "translate.glossary.networkError": "Netwerkfout", + "translate.glossary.importFailed": "Importeren mislukt ({status})", + "translate.glossary.helpText": "De woordenlijst dwingt nauwkeurige termvertaling af. Kies een woordenlijst waarvan de brontaal overeenkomt met de oorspronkelijke taal van uw document.", + "translate.glossary.sourceWarning": "Let op: Deze woordenlijst gebruikt brontaal", + "translate.glossary.sourceWarningBut": "maar uw document is geconfigureerd in", + "translate.glossary.targetWarning": "Doel incompatibiliteit: Deze woordenlijst is ontworpen om te vertalen naar", + "translate.glossary.targetWarningBut": "maar uw document is gericht op", + "translate.glossary.targetWarningEnd": "De termen zijn mogelijk niet relevant.", + "translate.header.processing": "Verwerking bezig", + "translate.header.aiActive": "AI-analyse actief", + "translate.header.aiActiveDesc": "Uw opmaak wordt behouden door onze contextuele engine.", + "translate.header.completed": "Voltooid", + "translate.header.completedTitle": "Vertaling voltooid", + "translate.header.proSpace": "Pro-ruimte", + "translate.header.translateDoc": "Een document vertalen", + "translate.header.translateDocDesc": "Behoud de originele opmaak met onze ultra-hoge-fidelity vertaalengine.", + "translate.upload.nativeFormat": "Native formaat", + "translate.fileType.word": "Word (.docx)", + "translate.fileType.excel": "Excel (.xlsx)", + "translate.fileType.slides": "Dia's (.pptx)", + "translate.fileType.pdf": "PDF (.pdf)", + "translate.startTranslation": "Vertaling starten", + "translate.submit": "Verzenden…", + "translate.chooseTargetLang": "Kies een doeltaal", + "translate.pleaseLoadFile": "Upload eerst een bestand", + "translate.contextEngineActive": "Contextuele engine actief", + "translate.phase1": "Fase 1: Initialisatie", + "translate.phase2": "Fase 2: Contextuele reconstructie", + "translate.stat.segments": "segmenten", + "translate.stat.precision": "precisie", + "translate.stat.speedLabel": "snelheid", + "translate.stat.turbo": "Turbo", + "translate.stat.time": "tijd", + "translate.complete.masterQuality": "✓ Meesterkwaliteit", + "translate.download": "Downloaden", + "translate.newTranslation": "+ Nieuwe vertaling", + "translate.failedTitle": "Vertaalfout", + "translate.retry": "Opnieuw", + "translate.uploadAnother": "Een ander bestand uploaden", + "translate.monitor": "AI-monitor", + "translate.summary": "Samenvatting", + "translate.cancelProcess": "⟳ Proces annuleren", + "translate.layoutIntegrity": "Lay-out integriteit", + "translate.secureHundred": "100% VEILIG", + "translate.okHundred": "100% OK", + "translate.preserveLayout": "Opmaak behouden", + "translate.preserveLayoutDesc": "Opmaak behouden", + "translate.textOnly": "Alleen tekst", + "translate.textOnlyDesc": "Snelle vertaling van alleen tekst", + "translate.unavailableStandard": "Niet beschikbaar in Standaardmodus (alleen AI)" +} diff --git a/frontend/src/lib/i18n/messages/nl/translateComplete.json b/frontend/src/lib/i18n/messages/nl/translateComplete.json new file mode 100644 index 0000000..382f54f --- /dev/null +++ b/frontend/src/lib/i18n/messages/nl/translateComplete.json @@ -0,0 +1,6 @@ +{ + "translateComplete.highQuality": "Hoge kwaliteit", + "translateComplete.segments": "Segmenten", + "translateComplete.characters": "Tekens", + "translateComplete.confidence": "Betrouwbaarheid" +} diff --git a/frontend/src/lib/i18n/messages/pt/admin.json b/frontend/src/lib/i18n/messages/pt/admin.json new file mode 100644 index 0000000..38e343e --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/admin.json @@ -0,0 +1,48 @@ +{ + "admin.login.title": "Administração", + "admin.login.required": "Login necessário", + "admin.login.password": "Senha de administrador", + "admin.login.connecting": "Conectando...", + "admin.login.access": "Acessar painel admin", + "admin.login.restricted": "Restrito a administradores", + "admin.layout.checking": "Verificando autenticação...", + "admin.dashboard.title": "Painel de Administração", + "admin.dashboard.subtitle": "Painel de controle do administrador", + "admin.dashboard.refresh": "Atualizar", + "admin.dashboard.refreshTooltip": "Atualizar dados do painel", + "admin.dashboard.config": "Configuração do sistema", + "admin.dashboard.maxFileSize": "Tamanho máximo do arquivo:", + "admin.dashboard.translationService": "Serviço de tradução:", + "admin.dashboard.formats": "Formatos:", + "admin.nav.dashboard": "Dashboard", + "admin.nav.users": "Usuários", + "admin.nav.pricing": "Preços e Stripe", + "admin.nav.providers": "Provedores", + "admin.nav.system": "Sistema", + "admin.nav.logs": "Registros", + "admin.users.title": "Gestão de Usuários", + "admin.users.subtitle": "Visualizar e gerenciar contas de usuários", + "admin.users.planUpdated": "Plano atualizado", + "admin.users.planChanged": "O plano foi alterado para \\\"{plan}\\\" com sucesso.", + "admin.users.unknownError": "Erro desconhecido", + "admin.users.error": "Erro", + "admin.users.planUpdateError": "Não foi possível atualizar o plano: {message}", + "admin.users.noKeys": "Sem chaves", + "admin.users.noKeysDesc": "Este usuário não tem chaves API ativas.", + "admin.users.keysRevoked": "Chaves revogadas", + "admin.users.keysRevokedDesc": "{count} chave(s) API revogada(s) com sucesso.", + "admin.users.revokeError": "Não foi possível revogar as chaves: {message}", + "admin.users.retry": "Tentar novamente", + "admin.system.title": "Sistema", + "admin.system.subtitle": "Monitorar o status do sistema e gerenciar recursos", + "admin.system.quotas": "Cotas de tradução", + "admin.system.resetQuotas": "Redefinir cotas mensais", + "admin.system.resetting": "Redefinindo...", + "admin.system.reset": "Redefinir", + "admin.system.allOperational": "Todos os sistemas operacionais", + "admin.system.issuesDetected": "Problemas no sistema detectados", + "admin.system.waitingData": "Aguardando dados...", + "admin.system.purging": "Limpando...", + "admin.system.clean": "Limpar", + "admin.system.purge": "Limpar" +} diff --git a/frontend/src/lib/i18n/messages/pt/apiKeys.json b/frontend/src/lib/i18n/messages/pt/apiKeys.json new file mode 100644 index 0000000..2949241 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/apiKeys.json @@ -0,0 +1,72 @@ +{ + "apiKeys.webhook.title": "Intégration Webhook", + "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", + "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", + "apiKeys.webhook.codeParam": "webhook_url", + "apiKeys.title": "Chaves de API", + "apiKeys.subtitle": "Gerencie suas chaves de API para acesso programático à API de tradução.", + "apiKeys.loading": "Carregando...", + "apiKeys.sectionTitle": "API e automação", + "apiKeys.sectionDesc": "Gere e gerencie suas chaves de API para fluxos de automação", + "apiKeys.keysUsed": "{total} de {max} chaves usadas", + "apiKeys.maxReached": "Máximo de chaves atingido. Revogue uma chave para gerar uma nova.", + "apiKeys.canGenerate": "Você pode gerar mais {count} chave", + "apiKeys.canGeneratePlural": "Você pode gerar mais {count} chaves", + "apiKeys.generateNew": "Gerar nova chave", + "apiKeys.keyRevoked": "Chave revogada", + "apiKeys.keyRevokedDesc": "A chave de API foi revogada com sucesso.", + "apiKeys.keyNotFound": "Chave não encontrada", + "apiKeys.keyNotFoundDesc": "A chave de API não existe mais. Ela pode ter sido revogada anteriormente.", + "apiKeys.error": "Erro", + "apiKeys.revokeError": "Falha ao revogar a chave de API. Tente novamente.", + "apiKeys.limitReached": "Limite atingido", + "apiKeys.limitReachedDesc": "Você atingiu o máximo de 10 chaves de API. Revogue uma chave existente para gerar uma nova.", + "apiKeys.proRequired": "Recurso Pro necessário", + "apiKeys.proRequiredDesc": "Chaves de API são um recurso Pro. Atualize sua conta.", + "apiKeys.generateError": "Falha ao gerar a chave de API. Tente novamente.", + "apiKeys.upgrade.title": "Chaves de API", + "apiKeys.upgrade.subtitle": "Automatize suas traduções com acesso à API", + "apiKeys.upgrade.feat1": "Gere chaves de API ilimitadas", + "apiKeys.upgrade.feat2": "Automatize a tradução de documentos", + "apiKeys.upgrade.feat3": "Notificações por webhook", + "apiKeys.upgrade.feat4": "Modos de tradução LLM", + "apiKeys.upgrade.proFeature": "Chaves de API são um recurso {pro}. Atualize para desbloquear a automação por API.", + "apiKeys.upgrade.pro": "Pro", + "apiKeys.upgrade.cta": "Atualizar para Pro", + "apiKeys.dialog.maxTitle": "Máximo de chaves atingido", + "apiKeys.dialog.maxDesc": "Você atingiu o máximo de 10 chaves de API. Revogue uma chave existente antes de gerar uma nova.", + "apiKeys.dialog.close": "Fechar", + "apiKeys.dialog.generated": "Chave de API gerada!", + "apiKeys.dialog.generatedDesc": "Sua nova chave de API foi criada. Copie-a agora — ela não será exibida novamente.", + "apiKeys.dialog.important": "Importante:", + "apiKeys.dialog.importantDesc": "Esta é a única vez que você verá esta chave. Armazene-a com segurança.", + "apiKeys.dialog.apiKey": "Chave de API", + "apiKeys.dialog.name": "Nome:", + "apiKeys.dialog.done": "Concluído", + "apiKeys.dialog.copied": "Já copiei a chave", + "apiKeys.dialog.generateTitle": "Gerar nova chave de API", + "apiKeys.dialog.generateDesc": "Crie uma nova chave de API para acesso programático à API de tradução.", + "apiKeys.dialog.keyName": "Nome da chave (opcional)", + "apiKeys.dialog.keyNamePlaceholder": "ex., Produção, Staging", + "apiKeys.dialog.keyNameHint": "Um nome descritivo para identificar esta chave posteriormente.", + "apiKeys.dialog.nameTooLong": "O nome deve ter {max} caracteres ou menos", + "apiKeys.dialog.nameInvalid": "O nome só pode conter letras, números, espaços, hifens e sublinhados", + "apiKeys.dialog.cancel": "Cancelar", + "apiKeys.dialog.generating": "Gerando...", + "apiKeys.dialog.generate": "Gerar chave", + "apiKeys.table.name": "Nome", + "apiKeys.table.prefix": "Prefixo", + "apiKeys.table.created": "Criada", + "apiKeys.table.lastUsed": "Último uso", + "apiKeys.table.never": "Nunca", + "apiKeys.table.actions": "Ações", + "apiKeys.table.revoke": "Revogar", + "apiKeys.table.copyPrefix": "Copiar prefixo da chave", + "apiKeys.table.revokeKey": "Revogar chave", + "apiKeys.revokeDialog.title": "Revogar chave de API", + "apiKeys.revokeDialog.desc": "Tem certeza de que deseja revogar a chave \\\"{name}\\\"? Esta ação não pode ser desfeita.", + "apiKeys.revokeDialog.confirm": "Sim, revogar", + "apiKeys.revokeDialog.cancel": "Cancelar", + "apiKeys.noKeysGenerated": "Nenhuma chave gerada", + "apiKeys.copied": "Copiado!" +} diff --git a/frontend/src/lib/i18n/messages/pt/auth.json b/frontend/src/lib/i18n/messages/pt/auth.json new file mode 100644 index 0000000..b300370 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/auth.json @@ -0,0 +1,3 @@ +{ + "auth.brandName": "Wordly" +} diff --git a/frontend/src/lib/i18n/messages/pt/checkout.json b/frontend/src/lib/i18n/messages/pt/checkout.json new file mode 100644 index 0000000..ecd12c0 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/checkout.json @@ -0,0 +1,12 @@ +{ + "checkout.activating": "A ativar…", + "checkout.activatingDesc": "Estamos a atualizar a sua assinatura, aguarde.", + "checkout.paymentConfirmed": "Pagamento confirmado!", + "checkout.subscriptionActivated": "Assinatura ativada!", + "checkout.planActivated": "Plano {plan} ativado!", + "checkout.redirectingToProfile": "A redirecionar para o seu perfil…", + "checkout.paymentReceived": "Pagamento recebido", + "checkout.redirecting": "A redirecionar…", + "checkout.syncError": "Erro de sincronização", + "checkout.networkError": "Erro de rede. O seu pagamento está confirmado — recarregue o seu perfil." +} diff --git a/frontend/src/lib/i18n/messages/pt/common.json b/frontend/src/lib/i18n/messages/pt/common.json new file mode 100644 index 0000000..e7d11df --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/common.json @@ -0,0 +1,4 @@ +{ + "common.loading": "Carregando...", + "common.backToHome": "Voltar ao início" +} diff --git a/frontend/src/lib/i18n/messages/pt/context.json b/frontend/src/lib/i18n/messages/pt/context.json new file mode 100644 index 0000000..d40087f --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/context.json @@ -0,0 +1,25 @@ +{ + "context.proTitle": "Recurso Pro", + "context.proDesc": "Contexto e glossários profissionais estão disponíveis nos planos Pro, Business e Enterprise. Eles fornecem traduções mais precisas através de instruções e vocabulário específico do seu domínio.", + "context.viewPlans": "Ver planos", + "context.title": "Contexto e glossário", + "context.subtitle": "Melhore a qualidade da tradução com instruções e vocabulário específico do seu domínio.", + "context.presets.title": "Glossários profissionais", + "context.presets.desc": "Carregue um glossário completo com instruções e terminologia especializada", + "context.instructions.title": "Instruções de contexto", + "context.instructions.desc": "Instruções que a IA seguirá durante a tradução", + "context.instructions.placeholder": "Ex.: Você traduz documentos técnicos de climatização. Use terminologia de engenharia precisa...", + "context.glossary.title": "Glossário técnico", + "context.glossary.desc": "Formato: origem=destino (um por linha). Glossários carregados via predefinição são editáveis.", + "context.glossary.terms": "termos no glossário", + "context.clearAll": "Limpar tudo", + "context.saving": "Salvando...", + "context.save": "Salvar", + "context.presets.createGlossary": "Criar glossário", + "context.presets.created": "Glossário criado", + "context.presets.createdDesc": "O glossário \\\"{name}\\\" foi criado com {count} termos.", + "context.presets.hint": "Clique em um preset para criar um glossário com termos específicos do domínio. Gerencie seus glossários na seção Glossários.", + "context.glossary.manage": "Gerenciar glossários", + "context.saved": "Salvo", + "context.savedDesc": "Suas instruções de contexto foram salvas." +} diff --git a/frontend/src/lib/i18n/messages/pt/cookieConsent.json b/frontend/src/lib/i18n/messages/pt/cookieConsent.json new file mode 100644 index 0000000..c787c71 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/cookieConsent.json @@ -0,0 +1,7 @@ +{ + "cookieConsent.title": "Cookies no Wordly", + "cookieConsent.description": "Usamos cookies essenciais para o funcionamento do serviço (sessão, segurança, idioma). Com a sua permissão, também usamos cookies opcionais para medir o tráfego e melhorar o produto.", + "cookieConsent.acceptAll": "Aceitar todas", + "cookieConsent.essentialOnly": "Apenas essenciais", + "cookieConsent.learnMore": "Saiba mais" +} diff --git a/frontend/src/lib/i18n/messages/pt/dashboard.json b/frontend/src/lib/i18n/messages/pt/dashboard.json new file mode 100644 index 0000000..51911ac --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/dashboard.json @@ -0,0 +1,111 @@ +{ + "dashboard.nav.translate": "Traduzir", + "dashboard.nav.profile": "Meu perfil", + "dashboard.nav.settings": "Configurações", + "dashboard.nav.context": "Contexto", + "dashboard.nav.services": "Serviços", + "dashboard.nav.apiKeys": "Chaves de API", + "dashboard.nav.glossaries": "Glossários", + "dashboard.header.title": "Painel", + "dashboard.header.subtitle": "Gerencie suas traduções", + "dashboard.header.toggleMenu": "Menu", + "dashboard.header.profileTitle": "Meu perfil", + "dashboard.sidebar.theme": "Tema", + "dashboard.sidebar.signOut": "Sair", + "dashboard.sidebar.backHome": "Voltar ao início", + "dashboard.sidebar.upgradeToPro": "Atualizar para Pro →", + "dashboard.translate.pageTitle": "Traduzir um documento", + "dashboard.translate.pageSubtitle": "Importe um arquivo e escolha o idioma de destino", + "dashboard.translate.errorNotificationTitle": "Erro", + "dashboard.translate.dropzone.uploadAria": "Área para soltar arquivos", + "dashboard.translate.dropzone.title": "Arraste e solte seu arquivo aqui", + "dashboard.translate.dropzone.subtitle": "ou clique para selecionar (DOCX, XLSX, PPTX, PDF)", + "dashboard.translate.dropzone.replaceFile": "Substituir arquivo", + "dashboard.translate.language.source": "Idioma de origem", + "dashboard.translate.language.target": "Idioma de destino", + "dashboard.translate.language.loading": "Carregando idiomas…", + "dashboard.translate.language.autoDetect": "Detecção automática", + "dashboard.translate.language.selectPlaceholder": "Selecionar…", + "dashboard.translate.language.loadErrorPrefix": "Erro ao carregar os idiomas", + "dashboard.translate.provider.loading": "Carregando provedores…", + "dashboard.translate.provider.noneConfigured": "Nenhum provedor configurado", + "dashboard.translate.provider.modelTitle": "Modelo", + "dashboard.translate.provider.sectionTitle": "Provedor", + "dashboard.translate.provider.llmDivider": "IA · Contextual", + "dashboard.translate.provider.llmDividerPro": "IA · Contextual (Pro)", + "dashboard.translate.provider.upgrade": "Fazer upgrade para Pro", + "dashboard.translate.provider.upgradeSuffix": "para desbloquear a tradução por IA", + "dashboard.translate.trust.zeroRetention": "Zero retenção", + "dashboard.translate.trust.deletedAfter": "Arquivos excluídos após o processamento", + "dashboard.translate.actions.uploading": "Enviando…", + "dashboard.translate.actions.translate": "Traduzir", + "dashboard.translate.actions.filePrefix": "Arquivo: ", + "dashboard.translate.actions.cancel": "Cancelar", + "dashboard.translate.actions.tryAgain": "Tentar novamente", + "dashboard.translate.steps.uploading": "Enviando arquivo…", + "dashboard.translate.steps.starting": "Iniciando tradução…", + "dashboard.translate.complete.title": "Tradução concluída!", + "dashboard.translate.complete.descNamed": "Seu arquivo {name} foi traduzido com sucesso.", + "dashboard.translate.complete.descGeneric": "Seu arquivo foi traduzido com sucesso.", + "dashboard.translate.complete.downloading": "Baixando…", + "dashboard.translate.complete.download": "Baixar", + "dashboard.translate.complete.newTranslation": "Nova tradução", + "dashboard.translate.complete.toastOkTitle": "Sucesso", + "dashboard.translate.complete.toastOkDesc": "{name} foi baixado com sucesso.", + "dashboard.translate.complete.toastFailTitle": "Falha", + "dashboard.translate.complete.toastFailDesc": "A tradução falhou. Por favor, tente novamente.", + "dashboard.translate.sourceDocument": "Documento fonte", + "dashboard.translate.configuration": "Configuração", + "dashboard.translate.translating": "Tradução em andamento", + "dashboard.translate.liveMonitor": "Monitor em tempo real", + "dashboard.translate.summary": "Resumo", + "dashboard.translate.engine": "Motor", + "dashboard.translate.confidence": "Confiança", + "dashboard.translate.cancel": "Cancelar", + "dashboard.translate.segments": "Segmentos", + "dashboard.translate.characters": "Caracteres", + "dashboard.translate.elapsed": "Decorrido", + "dashboard.translate.segPerMin": "Seg/min", + "dashboard.translate.highQuality": "Alta qualidade", + "dashboard.translate.quality": "Qualidade", + "dashboard.translate.completed": "Tradução concluída", + "dashboard.translate.replace": "Substituir", + "dashboard.translate.pdfMode.title": "Modo de tradução PDF", + "dashboard.translate.pdfMode.preserveLayout": "Preservar layout", + "dashboard.translate.pdfMode.textOnly": "Apenas texto", + "dashboard.translate.pdfMode.preserveLayoutDesc": "Mantém imagens, tabelas e formatação. Ideal para PDFs simples.", + "dashboard.translate.pdfMode.textOnlyDesc": "Traduz todo o texto perfeitamente. Saída limpa, sem problemas de layout.", + "dashboard.translate.pipeline.upload": "Enviar", + "dashboard.translate.pipeline.analyze": "Analisar", + "dashboard.translate.pipeline.translate": "Tradução", + "dashboard.translate.pipeline.rebuild": "Reconstruir", + "dashboard.translate.pipeline.finalize": "Finalizar", + "dashboard.translate.progress.processingFallback": "A processar…", + "dashboard.translate.progress.connectionLost": "Conexão perdida. A tentar novamente…", + "dashboard.translate.progress.failedTitle": "Tradução falhou", + "dashboard.translate.error.unexpected": "Ocorreu um erro inesperado. Tente novamente.", + "dashboard.translate.error.noResult": "A tradução não produziu resultados. Verifique se o documento contém texto e tente novamente ou escolha outro motor.", + "dashboard.translate.error.apiKey": "Chave de API inválida ou ausente. Contacte o administrador para configurar as chaves.", + "dashboard.translate.error.quota": "Limite de uso atingido. Tente novamente em alguns minutos ou escolha outro motor.", + "dashboard.translate.error.timeout": "A conexão ao serviço de tradução expirou. Verifique a sua rede e tente novamente.", + "dashboard.translate.error.sessionExpired": "Sessão expirada. Clique em Repetir para reiniciar a tradução.", + "dashboard.translate.error.empty": "O documento parece estar vazio ou não contém texto traduzível (PDF digitalizado?).", + "dashboard.translate.error.unsupported": "Formato de ficheiro não suportado ou ficheiro corrompido.", + "dashboard.translate.error.connection": "Conexão perdida. Verifique a sua rede e tente novamente.", + "dashboard.translate.error.generic": "Tradução falhou: {detail}", + "dashboard.translate.error.title": "Tradução falhou", + "dashboard.translate.retry": "Tentar novamente", + "dashboard.translate.newFile": "Novo ficheiro", + "dashboard.translate.modeAI": "Modo IA", + "dashboard.translate.modeClassic": "Modo Clássico", + "dashboard.translate.glossaryLLMHint": "Glossários disponíveis no modo IA", + "dashboard.translate.submitting": "A enviar...", + "dashboard.translate.submit": "Iniciar tradução", + "dashboard.translate.noFile": "Carregue um ficheiro primeiro", + "dashboard.translate.noTargetLang": "Selecione um idioma de destino", + "dashboard.topbar.interfaceLabel": "Interface de tradução", + "dashboard.topbar.premiumAccess": "Acesso Premium", + "dashboard.checkoutSyncError": "Erro ao sincronizar o pagamento.", + "dashboard.networkRefresh": "Erro de rede. Atualize a página.", + "dashboard.continueToTranslate": "Continuar para a tradução" +} diff --git a/frontend/src/lib/i18n/messages/pt/fileUploader.json b/frontend/src/lib/i18n/messages/pt/fileUploader.json new file mode 100644 index 0000000..52012f0 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/fileUploader.json @@ -0,0 +1,31 @@ +{ + "fileUploader.uploadDocument": "Carregar documento", + "fileUploader.uploadDesc": "Arraste e solte ou clique para selecionar um ficheiro (Excel, Word, PowerPoint)", + "fileUploader.dropHere": "Solte o ficheiro aqui…", + "fileUploader.dragAndDrop": "Arraste e solte o documento aqui", + "fileUploader.orClickBrowse": "ou clique para procurar", + "fileUploader.preview": "Pré-visualização", + "fileUploader.translationOptions": "Opções de tradução", + "fileUploader.configureSettings": "Configure as suas definições de tradução", + "fileUploader.targetLanguage": "Idioma de destino", + "fileUploader.selectLanguage": "Selecionar idioma", + "fileUploader.translationProvider": "Provedor de tradução", + "fileUploader.selectProvider": "Selecionar fornecedor", + "fileUploader.advancedOptions": "Opções avançadas", + "fileUploader.translateImages": "Traduzir imagens", + "fileUploader.translating": "A traduzir…", + "fileUploader.translateDocument": "Traduzir documento", + "fileUploader.processing": "A processar…", + "fileUploader.translationError": "Erro de tradução", + "fileUploader.translationComplete": "Tradução concluída!", + "fileUploader.translationCompleteDesc": "O seu documento foi traduzido com sucesso mantendo toda a formatação.", + "fileUploader.download": "Baixar documento traduzido", + "fileUploader.webgpuUnsupported": "WebGPU não é suportado neste navegador. Use Chrome 113+ ou Edge 113+.", + "fileUploader.webllmNotLoaded": "Modelo WebLLM não carregado. Vá a Definições > Serviços de tradução para carregar um modelo.", + "fileUploader.extracting": "A extrair textos do documento…", + "fileUploader.noTranslatable": "Nenhum texto traduzível encontrado no documento", + "fileUploader.foundTexts": "Encontrados {count} textos para traduzir", + "fileUploader.translatingItem": "A traduzir {current}/{total}: «{preview}»", + "fileUploader.reconstructing": "A reconstruir o documento…", + "fileUploader.translatingLocally": "A traduzir localmente com WebLLM…" +} diff --git a/frontend/src/lib/i18n/messages/pt/forgotPassword.json b/frontend/src/lib/i18n/messages/pt/forgotPassword.json new file mode 100644 index 0000000..0ac67c8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/forgotPassword.json @@ -0,0 +1,14 @@ +{ + "forgotPassword.enterEmail": "Please enter your email address", + "forgotPassword.error": "An error occurred", + "forgotPassword.title": "Forgot Password", + "forgotPassword.checkEmail": "Check your inbox", + "forgotPassword.subtitle": "Enter your email to receive a reset link", + "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", + "forgotPassword.emailLabel": "Email address", + "forgotPassword.emailPlaceholder": "you@example.com", + "forgotPassword.sending": "Sending...", + "forgotPassword.sendLink": "Send reset link", + "forgotPassword.backToLogin": "Back to login", + "forgotPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/pt/glossaries.json b/frontend/src/lib/i18n/messages/pt/glossaries.json new file mode 100644 index 0000000..afbbae8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/glossaries.json @@ -0,0 +1,189 @@ +{ + "glossaries.yourGlossaries": "Seus glossários", + "glossaries.title": "Glossários e Contexto", + "glossaries.description": "Gerencie seus glossários e instruções de contexto para traduções mais precisas.", + "glossaries.createNew": "Criar novo", + "glossaries.empty": "Nenhum glossário", + "glossaries.emptyDesc": "Crie seu primeiro glossário ou carregue um preset profissional acima", + "glossaries.defineTerms": "termos", + "glossaries.aboutTitle": "Sobre glossários", + "glossaries.aboutDesc": "Os glossários permitem definir traduções exatas para termos específicos. Ao traduzir, os termos do glossário garantem traduções consistentes e precisas.", + "glossaries.aboutFormat": "Cada termo tem uma palavra fonte e traduções em vários idiomas. Selecione um glossário na página de tradução para aplicá-lo.", + "glossaries.toast.created": "Glossário criado", + "glossaries.toast.createdDesc": "O glossário \\\"{name}\\\" foi criado.", + "glossaries.toast.imported": "Glossário importado", + "glossaries.toast.importedDesc": "O glossário \\\"{name}\\\" foi importado.", + "glossaries.toast.updated": "Glossário atualizado", + "glossaries.toast.updatedDesc": "O glossário \\\"{name}\\\" foi atualizado.", + "glossaries.toast.deleted": "Glossário excluído", + "glossaries.toast.deletedDesc": "O glossário foi excluído.", + "glossaries.toast.error": "Erro", + "glossaries.toast.errorCreate": "Falha ao criar glossário", + "glossaries.toast.errorImport": "Falha ao importar glossário", + "glossaries.toast.errorUpdate": "Falha ao atualizar glossário", + "glossaries.toast.errorDelete": "Falha ao excluir glossário", + "glossaries.dialog.title": "Novo glossário", + "glossaries.dialog.description": "Crie um glossário para suas traduções", + "glossaries.dialog.nameLabel": "Nome", + "glossaries.dialog.namePlaceholder": "Meu glossário", + "glossaries.dialog.tabTemplates": "Modelos", + "glossaries.dialog.tabFile": "Arquivo", + "glossaries.dialog.tabManual": "Manual", + "glossaries.dialog.cancel": "Cancelar", + "glossaries.dialog.creating": "Criando…", + "glossaries.dialog.importing": "Importando…", + "glossaries.dialog.importBtn": "Importar", + "glossaries.dialog.selectPrompt": "Selecionar", + "glossaries.dialog.createBtn": "Criar", + "glossaries.dialog.createEmpty": "Criar vazio", + "glossaries.dialog.terms": "termos", + "glossaries.dialog.templatesDesc": "Escolha um modelo predefinido", + "glossaries.dialog.templatesEmpty": "Nenhum modelo disponível", + "glossaries.dialog.dropTitle": "Arraste um arquivo CSV aqui", + "glossaries.dialog.dropOr": "ou", + "glossaries.dialog.dropFormats": "CSV, TSV, TXT", + "glossaries.termEditor.addTerm": "Adicionar termo", + "glossaries.termEditor.maxReached": "Máximo de {max} termos por glossário atingido.", + "glossaries.dialog.formatTitle": "Formato", + "glossaries.dialog.formatDesc": "origem,destino (um por linha)", + "glossaries.dialog.formatNote": "Primeira linha ignorada se houver cabeçalho", + "glossaries.dialog.errorFormat": "Formato não suportado", + "glossaries.dialog.errorSize": "Arquivo muito grande", + "glossaries.dialog.errorEmpty": "Arquivo vazio", + "glossaries.dialog.errorRead": "Erro de leitura", + "glossaries.dialog.parsing": "Analisando…", + "glossaries.dialog.termsImported": "termos importados", + "glossaries.dialog.changeFile": "Trocar arquivo", + "glossaries.dialog.retry": "Tentar novamente", + "glossaries.edit.title": "Modifier le glossaire", + "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", + "glossaries.edit.nameLabel": "Nom du glossaire", + "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", + "glossaries.edit.sourceLang": "Langue source", + "glossaries.edit.targetLang": "Langue cible", + "glossaries.edit.termsLabel": "Termes ({count} valides)", + "glossaries.edit.exportCsv": "Exporter CSV", + "glossaries.edit.importCsv": "Importer CSV", + "glossaries.edit.cancel": "Annuler", + "glossaries.edit.saving": "Enregistrement...", + "glossaries.edit.saveChanges": "Enregistrer les modifications", + "glossaries.edit.importFailedTitle": "Échec de l'importation", + "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", + "glossaries.edit.importSuccessTitle": "Importation réussie", + "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", + "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", + "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", + "glossaries.delete.title": "Supprimer le glossaire", + "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", + "glossaries.delete.warning": "Cette action est irréversible", + "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", + "glossaries.delete.cancel": "Annuler", + "glossaries.delete.deleting": "Suppression...", + "glossaries.delete.deleteBtn": "Supprimer", + "glossaries.upgrade.title": "Glossaires", + "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", + "glossaries.upgrade.feature1": "Créez plusieurs glossaires", + "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", + "glossaries.upgrade.feature3": "Importez/exportez via CSV", + "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", + "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", + "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", + "glossaries.upgrade.proLabel": "Pro", + "glossaries.upgrade.upgradeBtn": "Passer à Pro", + "glossaries.loading": "Chargement...", + "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", + "glossaries.howItWorks.step1Title": "Configurez ici", + "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", + "glossaries.howItWorks.step2Title": "Activez dans Traduire", + "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", + "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", + "glossaries.howItWorks.goToTranslate": "Aller à Traduire", + "glossaries.status.unsaved": "Non enregistré", + "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", + "glossaries.status.inactive": "Inactif", + "glossaries.instructions.whatForBold": "À quoi ça sert ?", + "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", + "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", + "glossaries.instructions.charCount": "{count} caractères", + "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", + "glossaries.instructions.clearAll": "Tout effacer", + "glossaries.instructions.saving": "Enregistrement…", + "glossaries.instructions.saved": "Enregistré", + "glossaries.presets.whatForBold": "À quoi ça sert ?", + "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", + "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", + "glossaries.presets.creating": "Création…", + "glossaries.presets.alreadyImported": "Déjà importé", + "glossaries.presets.it.title": "IT / Logiciel", + "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", + "glossaries.presets.legal.title": "Juridique / Contrats", + "glossaries.presets.legal.desc": "Droit des affaires, contentieux", + "glossaries.presets.medical.title": "Médical / Santé", + "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", + "glossaries.presets.finance.title": "Finance / Comptabilité", + "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", + "glossaries.presets.marketing.title": "Marketing / Publicité", + "glossaries.presets.marketing.desc": "Digital, branding, analytics", + "glossaries.presets.hr.title": "RH / Ressources Humaines", + "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", + "glossaries.presets.scientific.title": "Scientifique / Recherche", + "glossaries.presets.scientific.desc": "Publications, thèses, articles", + "glossaries.presets.ecommerce.title": "E-commerce / Vente", + "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", + "glossaries.grid.title": "Vos", + "glossaries.grid.titleHighlight": "glossaires", + "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", + "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", + "glossaries.grid.activeTranslation": "Traduction active :", + "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", + "glossaries.badge.compatible": "Compatible", + "glossaries.badge.otherTarget": "Autre cible", + "glossaries.card.editTerms": "Modifier les termes", + "glossaries.card.created": "Criado", + "glossaries.card.term": "termo", + "glossaries.card.delete": "Supprimer", + "glossaries.grid.searchPlaceholder": "Search a glossary…", + "glossaries.grid.noResults": "No results for this search.", + "glossaries.detail.backToList": "Back to glossaries", + "glossaries.detail.save": "Save", + "glossaries.detail.savedTitle": "Saved", + "glossaries.detail.savedDesc": "The glossary has been updated.", + "glossaries.detail.settingsTitle": "Settings", + "glossaries.detail.sourceLang": "Source language", + "glossaries.detail.targetLang": "Target language", + "glossaries.detail.termsTitle": "Terms", + "glossaries.detail.terms": "terms", + "glossaries.detail.searchTerms": "Filter…", + "glossaries.detail.noTerms": "No terms yet.", + "glossaries.detail.addFirstTerm": "Add the first term", + "glossaries.detail.addTerm": "Add a term", + "glossaries.detail.maxReached": "Maximum limit reached", + "glossaries.detail.source": "Source", + "glossaries.detail.target": "Target", + "glossaries.detail.sourcePlaceholder": "source term", + "glossaries.detail.targetPlaceholder": "target term", + "glossaries.detail.csvTitle": "CSV", + "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", + "glossaries.detail.export": "Export", + "glossaries.detail.import": "Import", + "glossaries.detail.dangerTitle": "Danger zone", + "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", + "glossaries.detail.deleteGlossary": "Delete this glossary", + "glossaries.detail.confirmDelete": "Confirm deletion?", + "glossaries.detail.confirm": "Confirm", + "glossaries.detail.cancel": "Cancel", + "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", + "glossaries.detail.sourceLocked": "fixed", + "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", + "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", + "glossaries.detail.notFoundTitle": "Glossary not found", + "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", + "glossaries.detail.maxTermsTitle": "Limit reached", + "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", + "glossaries.detail.importEmptyTitle": "Empty file", + "glossaries.detail.importEmptyDesc": "No terms detected in this file.", + "glossaries.detail.importedTitle": "Imported", + "glossaries.detail.importedDesc": "{count} terms imported.", + "glossaries.detail.importErrorTitle": "Read error", + "glossaries.detail.importErrorDesc": "Unable to read the file." +} diff --git a/frontend/src/lib/i18n/messages/pt/index.ts b/frontend/src/lib/i18n/messages/pt/index.ts new file mode 100644 index 0000000..25e7a95 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/index.ts @@ -0,0 +1,60 @@ +// Auto-generated by scripts/generate_i18n_index.py +// Merges all namespace JSON files for locale "pt". + +import admin from "./admin.json"; +import apiKeys from "./apiKeys.json"; +import auth from "./auth.json"; +import checkout from "./checkout.json"; +import common from "./common.json"; +import context from "./context.json"; +import cookieConsent from "./cookieConsent.json"; +import dashboard from "./dashboard.json"; +import fileUploader from "./fileUploader.json"; +import forgotPassword from "./forgotPassword.json"; +import glossaries from "./glossaries.json"; +import landing from "./landing.json"; +import langSelector from "./langSelector.json"; +import layout from "./layout.json"; +import login from "./login.json"; +import memento from "./memento.json"; +import pricing from "./pricing.json"; +import profile from "./profile.json"; +import providerSelector from "./providerSelector.json"; +import providerTheme from "./providerTheme.json"; +import register from "./register.json"; +import resetPassword from "./resetPassword.json"; +import services from "./services.json"; +import settings from "./settings.json"; +import translate from "./translate.json"; +import translateComplete from "./translateComplete.json"; + +const messages: Record = { + ...admin, + ...apiKeys, + ...auth, + ...checkout, + ...common, + ...context, + ...cookieConsent, + ...dashboard, + ...fileUploader, + ...forgotPassword, + ...glossaries, + ...landing, + ...langSelector, + ...layout, + ...login, + ...memento, + ...pricing, + ...profile, + ...providerSelector, + ...providerTheme, + ...register, + ...resetPassword, + ...services, + ...settings, + ...translate, + ...translateComplete, +}; + +export default messages; diff --git a/frontend/src/lib/i18n/messages/pt/landing.json b/frontend/src/lib/i18n/messages/pt/landing.json new file mode 100644 index 0000000..b7d9b97 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/landing.json @@ -0,0 +1,146 @@ +{ + "landing.nav.why": "Por que nós?", + "landing.nav.formats": "Formatos", + "landing.nav.pricing": "Preços", + "landing.nav.login": "Entrar", + "landing.nav.startFree": "Teste grátis", + "landing.hero.tag": "IA Documental Profissional", + "landing.hero.titleLine1": "Traduza seus documentos.", + "landing.hero.titleLine2": "Com formatação perfeita.", + "landing.hero.description": "O único tradutor que preserva SmartArt, gráficos, sumários, formas e layouts complexos — exatamente como eram.", + "landing.hero.ctaMain": "Teste grátis — 2 docs/mês", + "landing.hero.ctaSec": "Ver ofertas", + "landing.hero.deleted": "Arquivos excluídos após 60 min", + "landing.hero.noHidden": "Sem taxas ocultas", + "landing.hero.preview": "Visualização antes do pagamento", + "landing.hero.formattedOk": "Formatação OK", + "landing.hero.aiActive": "Tradução IA ativa", + "landing.steps.title": "Como funciona?", + "landing.steps.subtitle": "Três passos. Zero perda de formato.", + "landing.steps.step1.num": "01", + "landing.steps.step1.title": "Envie seu arquivo", + "landing.steps.step1.desc": "Arraste e solte seu documento Excel, Word, PowerPoint ou PDF.", + "landing.steps.step2.num": "02", + "landing.steps.step2.title": "Escolha idioma e motor", + "landing.steps.step2.desc": "Selecione o idioma de destino e o motor — clássico ou IA contextual.", + "landing.steps.step3.num": "03", + "landing.steps.step3.title": "Baixe o resultado", + "landing.steps.step3.desc": "Receba seu documento traduzido com formatação idêntica ao original.", + "landing.features.tag": "Motor de Tradução IA", + "landing.features.title": "Uma tradução que entende o seu ofício", + "landing.features.description": "Nossos modelos de IA analisam o contexto, respeitam sua terminologia e até traduzem texto dentro de imagens.", + "landing.features.context.title": "Contexto setorial", + "landing.features.context.desc": "Descreva seu setor e receba traduções adaptadas, não genéricas.", + "landing.features.glossary.title": "Glossários setoriais", + "landing.features.glossary.desc": "Defina seus termos técnicos. CTA será «Unidade de Tratamento de Ar», nunca «Chamada para Ação».", + "landing.features.vision.title": "Visão de imagens", + "landing.features.vision.desc": "Texto incorporado em imagens, diagramas e gráficos é detectado e traduzido.", + "landing.features.demo.source": "Origem (FR)", + "landing.features.demo.google": "Google Translate", + "landing.features.demo.ours": "Nossa IA", + "landing.layout.title": "Sua formatação,", + "landing.layout.title2": "perfeitamente preservada", + "landing.layout.subtitle": "Outros tradutores quebram seu layout. Nós não.", + "landing.layout.p1.title": "SmartArt e diagramas", + "landing.layout.p1.desc": "Organogramas, fluxogramas, hierarquias — tudo traduzido de forma idêntica.", + "landing.layout.p2.title": "Sumários", + "landing.layout.p2.desc": "Entradas do sumário, números de página e referências cruzadas atualizados corretamente.", + "landing.layout.p3.title": "Gráficos e diagramas", + "landing.layout.p3.desc": "Títulos, rótulos de eixos, legendas e nomes de séries — tudo traduzido.", + "landing.layout.p4.title": "Formas e caixas de texto", + "landing.layout.p4.desc": "Retângulos, blocos arredondados, balões — localizados em todo lugar.", + "landing.layout.p5.title": "Cabeçalhos e rodapés", + "landing.layout.p5.desc": "Cabeçalhos, rodapés e notas de rodapé nunca são esquecidos.", + "landing.layout.p6.title": "130+ idiomas", + "landing.layout.p6.desc": "Google Tradutor, DeepL e motores de IA de nível profissional.", + "landing.formats.title": "Cada formato,", + "landing.formats.title2": "cada elemento", + "landing.formats.subtitle": "Traduzimos o que os outros esquecem. Sua empresa merece documentação impecável.", + "landing.formats.word.name": "Word", + "landing.formats.word.i1": "Parágrafos e títulos", + "landing.formats.word.i2": "Tabelas e gráficos", + "landing.formats.word.i3": "Diagramas SmartArt", + "landing.formats.word.i4": "Sumário", + "landing.formats.word.i5": "Cabeçalhos e rodapés", + "landing.formats.word.i6": "Formas e caixas de texto", + "landing.formats.word.i7": "Notas de rodapé e finais", + "landing.formats.excel.name": "Excel", + "landing.formats.excel.i1": "Valores de células", + "landing.formats.excel.i2": "Nomes de planilhas", + "landing.formats.excel.i3": "Gráficos e rótulos", + "landing.formats.excel.i4": "Cabeçalhos e rodapés", + "landing.formats.excel.i5": "Células mescladas preservadas", + "landing.formats.pptx.name": "PowerPoint", + "landing.formats.pptx.i1": "Texto de slides e notas", + "landing.formats.pptx.i2": "Gráficos e diagramas", + "landing.formats.pptx.i3": "Formas e caixas de texto", + "landing.formats.pptx.i4": "Layouts mestres", + "landing.formats.pptx.i5": "Animações preservadas", + "landing.formats.pdf.name": "PDF", + "landing.formats.pdf.i1": "PDFs baseados em texto", + "landing.formats.pdf.i2": "Layout preservado", + "landing.formats.pdf.i3": "Imagens mantidas no lugar", + "landing.formats.pdf.i4": "Tabelas mantidas", + "landing.formats.pdf.i5": "Saída como DOCX ou PDF", + "landing.pricing.title": "Preços simples e honestos", + "landing.pricing.subtitle": "O que você vê é o que você paga. Sem taxas ocultas.", + "landing.pricing.monthly": "Mensal", + "landing.pricing.annual": "Anual", + "landing.pricing.bestValue": "Mais popular", + "landing.pricing.month": "/mês", + "landing.pricing.footer": "O preço exibido é o preço que você paga. Sem taxas ocultas após a tradução.", + "landing.pricing.starter.name": "Starter", + "landing.pricing.starter.desc": "Para pessoas físicas e projetos pequenos", + "landing.pricing.starter.f1": "50 documentos / mês", + "landing.pricing.starter.f2": "Até 50 páginas por doc", + "landing.pricing.starter.f3": "Google Tradutor + DeepL", + "landing.pricing.starter.f4": "Arquivos de até 10 MB", + "landing.pricing.starter.cta": "Começar", + "landing.pricing.pro.name": "Pro", + "landing.pricing.pro.desc": "Para profissionais exigentes", + "landing.pricing.pro.f1": "200 documentos / mês", + "landing.pricing.pro.f2": "Até 200 páginas por doc", + "landing.pricing.pro.f3": "Tradução com IA", + "landing.pricing.pro.f4": "Google + DeepL incluídos", + "landing.pricing.pro.f5": "Glossários e prompts personalizados", + "landing.pricing.pro.f6": "Suporte prioritário", + "landing.pricing.pro.cta": "Testar Pro", + "landing.pricing.business.name": "Business", + "landing.pricing.business.desc": "Para equipes com alto volume", + "landing.pricing.business.f1": "1 000 documentos / mês", + "landing.pricing.business.f2": "Até 500 páginas por doc", + "landing.pricing.business.f3": "IA Premium (Claude)", + "landing.pricing.business.f4": "Todos os provedores + API", + "landing.pricing.business.f5": "Webhooks e automação", + "landing.pricing.business.f6": "5 assentos de equipe", + "landing.pricing.business.cta": "Fale conosco", + "landing.cta.title": "Comece a traduzir em 30 segundos", + "landing.cta.subtitle": "Nenhum cartão de crédito necessário. Experimente grátis agora e dê vida aos seus documentos multilíngues.", + "landing.cta.button": "Criar conta gratuita", + "landing.cta.secure": "Protegido por criptografia AES-256", + "landing.footer.desc": "Especialista em tradução inteligente de documentos. Combinamos a arte do layout com a ciência da IA contextual.", + "landing.footer.product": "Produto", + "landing.footer.resources": "Recursos", + "landing.footer.legal": "Legal", + "landing.footer.rights": "© 2026 Wordly.art — Todos os direitos reservados.", + "landing.hero.contextEngine": "Tradução detectada: Termo técnico de manutenção para sistemas HVAC...", + "landing.hero.liveAnalysis": "Análise em tempo real", + "landing.hero.termsDetected": "termos detectados", + "landing.steps.process": "PROCESSO", + "landing.translate.newProject": "Novo projeto", + "landing.translate.title": "Traduzir um documento", + "landing.translate.subtitle": "Importe um arquivo e escolha o idioma de destino", + "landing.translate.sourceDocument": "Documento fonte", + "landing.translate.configuration": "Configuração", + "landing.translate.sourceLang": "Idioma de origem", + "landing.translate.targetLang": "Idioma de destino", + "landing.translate.provider": "Fornecedor", + "landing.translate.startTranslation": "Iniciar tradução", + "landing.translate.zeroRetention": "Retenção zero", + "landing.translate.filesDeleted": "Ficheiros eliminados após processamento", + "landing.translate.dropHere": "Arraste e solte aqui", + "landing.translate.supportedFormats": "Ficheiros DOCX, XLSX, PPTX ou PDF suportados", + "landing.translate.aiAnalysis": "Análise IA Ativa", + "landing.translate.processing": "Em processamento", + "landing.translate.preservingLayout": "O seu layout está a ser preservado" +} diff --git a/frontend/src/lib/i18n/messages/pt/langSelector.json b/frontend/src/lib/i18n/messages/pt/langSelector.json new file mode 100644 index 0000000..cfc2f3f --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/langSelector.json @@ -0,0 +1,7 @@ +{ + "langSelector.search": "Pesquisar…", + "langSelector.noResults": "Sem resultados", + "langSelector.source": "Origem", + "langSelector.target": "Destino", + "langSelector.swap": "Trocar" +} diff --git a/frontend/src/lib/i18n/messages/pt/layout.json b/frontend/src/lib/i18n/messages/pt/layout.json new file mode 100644 index 0000000..55aadf1 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/layout.json @@ -0,0 +1,5 @@ +{ + "layout.nav.apiAccess": "Acesso à API", + "layout.footer.terms": "Termos", + "layout.footer.privacy": "Privacidade" +} diff --git a/frontend/src/lib/i18n/messages/pt/login.json b/frontend/src/lib/i18n/messages/pt/login.json new file mode 100644 index 0000000..1c1f4e1 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/login.json @@ -0,0 +1,18 @@ +{ + "login.errorTitle": "Login Error", + "login.welcomeBack": "Welcome back", + "login.signInToContinue": "Sign in to continue translating", + "login.email": "Email", + "login.emailPlaceholder": "you@example.com", + "login.password": "Password", + "login.forgotPassword": "Forgot password?", + "login.passwordPlaceholder": "••••••••", + "login.signingIn": "Signing in...", + "login.signIn": "Sign In", + "login.noAccount": "Don't have an account?", + "login.signUpFree": "Sign up for free", + "login.orContinueWith": "ou continuar com e-mail", + "login.google.connecting": "A ligar…", + "login.google.errorGeneric": "Ocorreu um erro no início de sessão com Google.", + "login.google.errorFailed": "Falha no início de sessão com Google. Tente novamente." +} diff --git a/frontend/src/lib/i18n/messages/pt/memento.json b/frontend/src/lib/i18n/messages/pt/memento.json new file mode 100644 index 0000000..26dfc21 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/memento.json @@ -0,0 +1,6 @@ +{ + "memento.title": "Descubra o Momento", + "memento.slogan": "O Momento é mais do que uma aplicação de notas. É um ecossistema inteligente que conecta, analisa e desenvolve suas ideias em tempo real usando 6 agentes de IA e busca semântica avançada.", + "memento.ctaFree": "Começar grátis", + "memento.ctaMore": "Saiba mais" +} diff --git a/frontend/src/lib/i18n/messages/pt/pricing.json b/frontend/src/lib/i18n/messages/pt/pricing.json new file mode 100644 index 0000000..3749102 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/pricing.json @@ -0,0 +1,151 @@ +{ + "pricing.nav.back": "Voltar", + "pricing.nav.home": "Início", + "pricing.nav.mySubscription": "Minha assinatura", + "pricing.header.badge": "Modelos de IA atualizados — Março 2026", + "pricing.header.title": "Um plano para cada necessidade", + "pricing.header.subtitle": "Traduza seus documentos Word, Excel e PowerPoint preservando a formatação original. Sem necessidade de chave de API.", + "pricing.billing.monthly": "Mensal", + "pricing.billing.yearly": "Anual", + "pricing.plans.free.name": "Gratuito", + "pricing.plans.starter.name": "Starter", + "pricing.plans.pro.name": "Pro", + "pricing.plans.business.name": "Business", + "pricing.plans.enterprise.name": "Enterprise", + "pricing.plans.free.description": "Perfeito para conhecer o aplicativo", + "pricing.plans.starter.description": "Para pessoas físicas e projetos pequenos", + "pricing.plans.pro.description": "Para profissionais e equipes em crescimento", + "pricing.plans.business.description": "Para equipes e organizações", + "pricing.plans.enterprise.description": "Soluções personalizadas para grandes organizações", + "pricing.plans.pro.highlight": "Mais popular", + "pricing.plans.pro.badge": "POPULAR", + "pricing.plans.enterprise.badge": "SOB CONSULTA", + "pricing.plans.free.feat1": "5 documentos / mês", + "pricing.plans.free.feat2": "Até 15 páginas por documento", + "pricing.plans.free.feat3": "Google Tradutor incluído", + "pricing.plans.free.feat4": "Todos os idiomas (130+)", + "pricing.plans.free.feat5": "Suporte da comunidade", + "pricing.plans.starter.feat1": "50 documentos / mês", + "pricing.plans.starter.feat2": "Até 50 páginas por documento", + "pricing.plans.starter.feat3": "Google Tradutor + DeepL", + "pricing.plans.starter.feat4": "Arquivos de até 10 MB", + "pricing.plans.starter.feat5": "Suporte por e-mail", + "pricing.plans.starter.feat6": "Histórico de 30 dias", + "pricing.plans.pro.feat1": "200 documentos / mês", + "pricing.plans.pro.feat2": "Até 200 páginas por documento", + "pricing.plans.pro.feat3": "Tradução IA Essencial", + "pricing.plans.pro.feat4": "Google Tradutor + DeepL", + "pricing.plans.pro.feat5": "Arquivos de até 25 MB", + "pricing.plans.pro.feat6": "Glossários personalizados", + "pricing.plans.pro.feat7": "Suporte prioritário", + "pricing.plans.pro.feat8": "Histórico de 90 dias", + "pricing.plans.business.feat1": "1 000 documentos / mês", + "pricing.plans.business.feat2": "Até 500 páginas por documento", + "pricing.plans.business.feat3": "IA Essencial + Premium (Claude Haiku)", + "pricing.plans.business.feat4": "Todos os provedores de tradução", + "pricing.plans.business.feat5": "Arquivos de até 50 MB", + "pricing.plans.business.feat6": "Acesso à API (10 000 chamadas/mês)", + "pricing.plans.business.feat7": "Webhooks de notificação", + "pricing.plans.business.feat8": "Suporte dedicado", + "pricing.plans.business.feat9": "Histórico de 1 ano", + "pricing.plans.business.feat10": "Análises avançadas", + "pricing.plans.enterprise.feat1": "Documentos ilimitados", + "pricing.plans.enterprise.feat2": "Todos os modelos de IA (GPT-5, Claude Opus 4.6…)", + "pricing.plans.enterprise.feat3": "Implantação local ou em nuvem dedicada", + "pricing.plans.enterprise.feat4": "SLA 99,9 % garantido", + "pricing.plans.enterprise.feat5": "Suporte dedicado 24/7", + "pricing.plans.enterprise.feat6": "Marca branca (white-label)", + "pricing.plans.enterprise.feat7": "Equipes ilimitadas", + "pricing.plans.enterprise.feat8": "Integrações personalizadas", + "pricing.card.onRequest": "Sob consulta", + "pricing.card.free": "Gratuito", + "pricing.card.perMonth": "/mês", + "pricing.card.billedYearly": "Cobrado {price} € / ano", + "pricing.card.documents": "Documentos", + "pricing.card.pagesMax": "Páginas máx.", + "pricing.card.aiTranslation": "Tradução por IA", + "pricing.card.unlimited": "Ilimitado", + "pricing.card.perMonthStat": "/ mês", + "pricing.card.perDoc": "p / doc", + "pricing.card.aiEssential": "Essencial", + "pricing.card.aiEssentialPremium": "Essencial + Premium", + "pricing.card.aiCustom": "Personalizado", + "pricing.card.myPlan": "Meu plano", + "pricing.card.managePlan": "Gerenciar meu plano", + "pricing.card.startFree": "Começar gratuitamente", + "pricing.card.contactUs": "Fale conosco", + "pricing.card.choosePlan": "Escolher este plano", + "pricing.card.processing": "Processando…", + "pricing.comparison.title": "Comparação detalhada", + "pricing.comparison.subtitle": "Tudo incluído em cada plano", + "pricing.comparison.feature": "Recurso", + "pricing.comparison.docsPerMonth": "Documentos / mês", + "pricing.comparison.pagesMaxPerDoc": "Páginas máx. / documento", + "pricing.comparison.maxFileSize": "Tamanho máx. de arquivo", + "pricing.comparison.googleTranslation": "Google Tradutor", + "pricing.comparison.deepl": "DeepL", + "pricing.comparison.aiEssential": "Tradução IA Essencial", + "pricing.comparison.aiPremium": "Tradução IA Premium", + "pricing.comparison.apiAccess": "Acesso à API", + "pricing.comparison.priorityProcessing": "Processamento prioritário", + "pricing.comparison.support": "Suporte", + "pricing.comparison.support.community": "Comunidade", + "pricing.comparison.support.email": "E-mail", + "pricing.comparison.support.priority": "Prioritário", + "pricing.comparison.support.dedicated": "Dedicado", + "pricing.comparison.mb": "MB", + "pricing.credits.title": "Créditos adicionais", + "pricing.credits.subtitle": "Precisa de mais? Compre créditos avulsos, sem assinatura.", + "pricing.credits.perPage": "1 crédito = 1 página traduzida.", + "pricing.credits.bestValue": "Melhor custo-benefício", + "pricing.credits.unit": "créditos", + "pricing.credits.centsPerCredit": "cts / crédito", + "pricing.credits.buy": "Comprar", + "pricing.trust.encryption.title": "Criptografia de ponta a ponta", + "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 em repouso", + "pricing.trust.languages.title": "130+ idiomas", + "pricing.trust.languages.sub": "Incluindo árabe, persa, hebraico (RTL)", + "pricing.trust.parallel.title": "Processamento paralelo", + "pricing.trust.parallel.sub": "IA multi-thread ultrarrápida", + "pricing.trust.availability.title": "Disponível 24/7", + "pricing.trust.availability.sub": "99,9 % de uptime garantido", + "pricing.aiModels.title": "Nossos modelos de IA — Março 2026", + "pricing.aiModels.essential.title": "Tradução IA Essencial", + "pricing.aiModels.essential.plan": "Plano Pro", + "pricing.aiModels.essential.descPrefix": "Baseado em", + "pricing.aiModels.essential.descSuffix": "— o modelo de IA mais econômico de 2026. Qualidade comparável a modelos frontier a uma fração do custo.", + "pricing.aiModels.essential.modelName": "nosso modelo IA Essencial", + "pricing.aiModels.essential.context": "163K tokens de contexto", + "pricing.aiModels.essential.value": "Excelente custo-benefício", + "pricing.aiModels.premium.title": "Tradução IA Premium", + "pricing.aiModels.premium.plan": "Plano Business", + "pricing.aiModels.premium.descPrefix": "Baseado em", + "pricing.aiModels.premium.descSuffix": "da Anthropic — preciso em documentos jurídicos, médicos e técnicos complexos.", + "pricing.aiModels.premium.context": "200K tokens de contexto", + "pricing.aiModels.premium.precision": "Maior precisão", + "pricing.faq.title": "Perguntas frequentes", + "pricing.faq.q1": "Posso trocar de plano a qualquer momento?", + "pricing.faq.a1": "Sim. O upgrade é imediato e proporcional. O downgrade entra em vigor no final do período atual.", + "pricing.faq.q2": "O que é a «Tradução IA Essencial»?", + "pricing.faq.a2": "É nosso motor de IA. Ele compreende o contexto dos seus documentos, preserva a formatação e lida com termos técnicos muito melhor do que a tradução clássica.", + "pricing.faq.q3": "Qual a diferença entre IA Essencial e IA Premium?", + "pricing.faq.a3": "A IA Essencial usa um modelo otimizado (excelente custo-benefício). A IA Premium usa Claude 3.5 Haiku da Anthropic, mais precisa em documentos jurídicos, médicos e técnicos complexos.", + "pricing.faq.q4": "Meus documentos são mantidos após a tradução?", + "pricing.faq.a4": "Os arquivos traduzidos ficam disponíveis de acordo com seu plano (30 dias Starter, 90 dias Pro, 1 ano Business). São criptografados em repouso e em trânsito.", + "pricing.faq.q5": "O que acontece se eu exceder minha cota mensal?", + "pricing.faq.a5": "Você pode comprar créditos avulsos ou fazer upgrade do plano. Você será notificado ao atingir 80 % de uso.", + "pricing.faq.q6": "Existe um teste gratuito para os planos pagos?", + "pricing.faq.a6": "O plano Gratuito é permanente e não exige cartão. Para os planos Pro e Business, entre em contato para um teste de 14 dias.", + "pricing.faq.q7": "Quais formatos de arquivo são suportados?", + "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx) e em breve PDF. Todos os planos suportam os mesmos formatos.", + "pricing.cta.title": "Pronto para começar?", + "pricing.cta.subtitle": "Comece gratuitamente, sem cartão de crédito. Faça upgrade quando precisar.", + "pricing.cta.createAccount": "Criar uma conta gratuita", + "pricing.cta.login": "Entrar", + "pricing.toast.demo": "Modo demo — O Stripe ainda não está configurado. Em produção, você seria redirecionado para o pagamento para ativar o plano {planId}.", + "pricing.toast.networkError": "Erro de rede. Por favor, tente novamente.", + "pricing.toast.paymentError": "Erro ao criar o pagamento.", + "pricing.dashboard": "Painel", + "pricing.okSymbol": "✓", + "pricing.errSymbol": "✕" +} diff --git a/frontend/src/lib/i18n/messages/pt/profile.json b/frontend/src/lib/i18n/messages/pt/profile.json new file mode 100644 index 0000000..6ea591d --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/profile.json @@ -0,0 +1,58 @@ +{ + "profile.header.title": "Meu perfil", + "profile.header.subtitle": "Gerencie sua conta e preferências.", + "profile.tabs.account": "Conta", + "profile.tabs.subscription": "Assinatura", + "profile.tabs.preferences": "Preferências", + "profile.account.user": "Usuário", + "profile.account.memberSince": "Membro desde", + "profile.plan.label": "Plano", + "profile.plan.free": "Gratuito", + "profile.plan.starter": "Starter", + "profile.plan.pro": "Pro", + "profile.plan.business": "Business", + "profile.plan.enterprise": "Enterprise", + "profile.plan.pricePerMonth": "{price} €/mês", + "profile.subscription.canceling": "Cancelando", + "profile.subscription.active": "Ativa", + "profile.subscription.unknown": "Desconhecido", + "profile.subscription.accessUntil": "Acesso até", + "profile.subscription.renewalOn": "Renovação em", + "profile.subscription.upgradePlan": "Atualizar para um plano pago", + "profile.subscription.changePlan": "Alterar plano", + "profile.subscription.manageBilling": "Gerenciar cobrança", + "profile.subscription.billingUnavailable": "Portal de cobrança indisponível.", + "profile.subscription.billingError": "Erro ao acessar o portal de cobrança.", + "profile.subscription.cancelSuccess": "Assinatura cancelada. Você mantém o acesso até o final do período.", + "profile.subscription.cancelError": "Erro durante o cancelamento.", + "profile.subscription.networkError": "Erro de rede.", + "profile.usage.title": "Uso este mês", + "profile.usage.resetOn": "Redefinição em", + "profile.usage.documents": "Documentos", + "profile.usage.pages": "Páginas", + "profile.usage.extraCredits": "crédito extra", + "profile.usage.extraCreditsPlural": "créditos extras", + "profile.usage.quotaReached": "Cota atingida", + "profile.usage.quotaReachedDesc": "Atualize para um plano superior para continuar.", + "profile.usage.unlockMore": "Desbloqueie mais traduções com um plano pago.", + "profile.usage.viewPlans": "Ver planos", + "profile.usage.includedInPlan": "Incluído no seu plano", + "profile.danger.title": "Zona de perigo", + "profile.danger.description": "O cancelamento entra em vigor no final do seu período atual. Você mantém o acesso até essa data.", + "profile.danger.confirm": "Tem certeza? Esta ação não pode ser desfeita.", + "profile.danger.confirmCancel": "Confirmar cancelamento", + "profile.danger.cancelSubscription": "Cancelar minha assinatura", + "profile.danger.keep": "Não, manter", + "profile.prefs.interfaceLang": "Idioma da interface", + "profile.prefs.interfaceLangDesc": "O idioma é detectado automaticamente com base no seu navegador. Você pode alterá-lo manualmente.", + "profile.prefs.defaultTargetLang": "Idioma de destino padrão", + "profile.prefs.selectLanguage": "Selecione um idioma", + "profile.prefs.defaultTargetLangDesc": "Este idioma será pré-selecionado para suas traduções.", + "profile.prefs.save": "Salvar", + "profile.prefs.theme": "Tema", + "profile.prefs.themeDesc": "Escolha a aparência da interface", + "profile.prefs.cache": "Cache", + "profile.prefs.cacheDesc": "Limpar o cache local pode corrigir alguns problemas de exibição.", + "profile.prefs.clearing": "Limpando...", + "profile.prefs.clearCache": "Limpar cache" +} diff --git a/frontend/src/lib/i18n/messages/pt/providerSelector.json b/frontend/src/lib/i18n/messages/pt/providerSelector.json new file mode 100644 index 0000000..8dc7874 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/providerSelector.json @@ -0,0 +1,7 @@ +{ + "providerSelector.noClassic": "Nenhum tradutor padrão disponível.", + "providerSelector.noLlm": "Nenhum modelo de IA configurado.", + "providerSelector.costOne": "Custo: 1 crédito por página", + "providerSelector.costFive": "Custo: 5 créditos por página (Fator Premium)", + "providerSelector.unlockContextual": "Desbloqueie a tradução contextual premium para os seus documentos completos." +} diff --git a/frontend/src/lib/i18n/messages/pt/providerTheme.json b/frontend/src/lib/i18n/messages/pt/providerTheme.json new file mode 100644 index 0000000..90c8c33 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/providerTheme.json @@ -0,0 +1,29 @@ +{ + "providerTheme.deepseek.badge": "Essencial", + "providerTheme.deepseek.subBadge": "Técnico e económico", + "providerTheme.deepseek.desc": "Tradução ultra-precisa e económica, ideal para documentos técnicos e código.", + "providerTheme.openai.badge": "Premium", + "providerTheme.openai.subBadge": "Alta fidelidade", + "providerTheme.openai.desc": "O padrão global de IA. Máxima consistência textual e respeito estrito do estilo.", + "providerTheme.minimax.badge": "Avançada", + "providerTheme.minimax.subBadge": "Desempenho", + "providerTheme.minimax.desc": "Velocidade de execução incrível e excelente compreensão de estruturas complexas.", + "providerTheme.openrouter.badge": "Expresso", + "providerTheme.openrouter.subBadge": "Multi-modelo", + "providerTheme.openrouter.desc": "Acesso unificado aos melhores modelos open-source otimizados para tradução.", + "providerTheme.openrouter_premium.badge": "Ultra", + "providerTheme.openrouter_premium.subBadge": "Contexto máximo", + "providerTheme.openrouter_premium.desc": "Assistido pelos modelos mais avançados (GPT-4o, Claude Sonnet 4.6) para documentos longos.", + "providerTheme.zai.badge": "Especializada", + "providerTheme.zai.subBadge": "Finanças e Direito", + "providerTheme.zai.desc": "Modelo afinado para terminologias empresariais exigentes (jurídico, financeiro).", + "providerTheme.default.badge": "Moderno", + "providerTheme.default.subBadge": "Raciocínio IA", + "providerTheme.default.desc": "Tradução por modelo de linguagem grande (LLM) com análise semântica avançada.", + "providerTheme.classic.google.label": "Google Tradutor", + "providerTheme.classic.google.desc": "Tradução ultra-rápida cobrindo mais de 130 idiomas. Recomendado para fluxos gerais.", + "providerTheme.classic.deepl.label": "DeepL Pro", + "providerTheme.classic.deepl.desc": "Tradução de alta precisão conhecida pela sua fluência e formulações naturais.", + "providerTheme.classic.google_cloud.label": "Google Cloud API", + "providerTheme.classic.google_cloud.desc": "Motor cloud profissional otimizado para processar grandes volumes de documentos." +} diff --git a/frontend/src/lib/i18n/messages/pt/register.json b/frontend/src/lib/i18n/messages/pt/register.json new file mode 100644 index 0000000..9e2bb06 --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/register.json @@ -0,0 +1,29 @@ +{ + "register.title": "Criar uma conta", + "register.subtitle": "Comece a traduzir gratuitamente", + "register.error.failed": "Falha no registro", + "register.name.label": "Nome", + "register.name.placeholder": "Seu nome", + "register.name.error": "O nome deve ter pelo menos 2 caracteres", + "register.email.label": "Endereço de e-mail", + "register.email.placeholder": "voce@exemplo.com", + "register.email.error": "Endereço de e-mail inválido", + "register.password.label": "Senha", + "register.password.error": "A senha deve ter pelo menos 8 caracteres, com uma letra maiúscula, uma minúscula e um dígito", + "register.password.show": "Mostrar senha", + "register.password.hide": "Ocultar senha", + "register.password.strengthLabel": "Força:", + "register.password.strength.weak": "Fraca", + "register.password.strength.medium": "Média", + "register.password.strength.strong": "Forte", + "register.confirmPassword.label": "Confirmar senha", + "register.confirmPassword.error": "As senhas não coincidem", + "register.confirmPassword.show": "Mostrar", + "register.confirmPassword.hide": "Ocultar", + "register.submit.creating": "Criando conta...", + "register.submit.create": "Criar minha conta", + "register.hasAccount": "Já tem uma conta?", + "register.login": "Entrar", + "register.terms.prefix": "Ao criar uma conta, você aceita nossos", + "register.terms.link": "termos de serviço" +} diff --git a/frontend/src/lib/i18n/messages/pt/resetPassword.json b/frontend/src/lib/i18n/messages/pt/resetPassword.json new file mode 100644 index 0000000..680714f --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/resetPassword.json @@ -0,0 +1,22 @@ +{ + "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", + "resetPassword.passwordMismatch": "Passwords do not match", + "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", + "resetPassword.error": "An error occurred", + "resetPassword.invalidLink": "Invalid link", + "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", + "resetPassword.requestNewLink": "Request new link", + "resetPassword.successTitle": "Password reset", + "resetPassword.newPasswordTitle": "New password", + "resetPassword.successSubtitle": "You will be redirected to login", + "resetPassword.subtitle": "Set your new password", + "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", + "resetPassword.newPassword": "New password", + "resetPassword.showPassword": "Show password", + "resetPassword.hidePassword": "Hide password", + "resetPassword.confirmPassword": "Confirm password", + "resetPassword.resetting": "Resetting...", + "resetPassword.resetPassword": "Reset password", + "resetPassword.backToLogin": "Back to login", + "resetPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/pt/services.json b/frontend/src/lib/i18n/messages/pt/services.json new file mode 100644 index 0000000..1b5f99b --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/services.json @@ -0,0 +1,14 @@ +{ + "services.title": "Provedores de tradução", + "services.subtitle": "Os provedores são configurados pelo administrador. Você pode ver quais estão disponíveis para sua conta.", + "services.loading": "Carregando provedores...", + "services.noProviders": "Nenhum provedor está configurado no momento. Entre em contato com seu administrador.", + "services.classic": "Tradução clássica", + "services.llmPro": "LLM · Contextual (Pro)", + "services.available": "Disponível", + "services.model": "Modelo", + "services.adminOnly.title": "A configuração de provedores é exclusiva do administrador", + "services.adminOnly.desc": "Chaves de API, seleção de modelos e ativação de provedores são gerenciadas exclusivamente pelo administrador no painel administrativo. Você nunca precisa inserir uma chave de API.", + "services.fallback.google.label": "Google Tradutor", + "services.fallback.google.desc": "Tradução rápida, mais de 130 idiomas" +} diff --git a/frontend/src/lib/i18n/messages/pt/settings.json b/frontend/src/lib/i18n/messages/pt/settings.json new file mode 100644 index 0000000..5244c5a --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/settings.json @@ -0,0 +1,20 @@ +{ + "settings.title": "Configurações", + "settings.subtitle": "Configuração geral do aplicativo", + "settings.formats.title": "Formatos suportados", + "settings.formats.subtitle": "Tipos de documentos que você pode traduzir", + "settings.formats.formulas": "Fórmulas", + "settings.formats.styles": "Estilos", + "settings.formats.images": "Imagens", + "settings.formats.headers": "Cabeçalhos", + "settings.formats.tables": "Tabelas", + "settings.formats.slides": "Slides", + "settings.formats.notes": "Notas", + "settings.cache.title": "Cache", + "settings.cache.desc": "Limpar o cache local pode corrigir alguns problemas de exibição.", + "settings.cache.clearing": "Limpando...", + "settings.cache.clear": "Limpar cache", + "settings.formats.excel.name": "Excel", + "settings.formats.word.name": "Word", + "settings.formats.powerpoint.name": "PowerPoint" +} diff --git a/frontend/src/lib/i18n/messages/pt/translate.json b/frontend/src/lib/i18n/messages/pt/translate.json new file mode 100644 index 0000000..83debdd --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/translate.json @@ -0,0 +1,92 @@ +{ + "translate.mode.label": "Mode de traduction", + "translate.mode.classic": "Classique", + "translate.mode.classicDesc": "Rapide", + "translate.mode.proLlm": "Pro LLM", + "translate.mode.proLlmDesc": "Contextuel", + "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", + "translate.mode.upgradeLink": "Passer à Pro", + "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", + "translate.glossary.title": "Glossário", + "translate.glossary.select": "Selecionar glossário", + "translate.glossary.none": "Nenhum", + "translate.glossary.terms": "termos", + "translate.glossary.proOnly": "Atualize para Pro para usar glossários", + "translate.glossary.myGlossaries": "Meus glossários", + "translate.glossary.fromTemplate": "Criar do modelo", + "translate.glossary.noGlossaryForPair": "Sem glossário para", + "translate.glossary.noGlossaries": "Sem glossários", + "translate.glossary.loading": "Carregando...", + "translate.glossary.classicMode": "Motor neutro sem glossário (apenas IA)", + "translate.glossary.selectPlaceholder": "Selecionar um glossário...", + "translate.glossary.multilingual": "MULTILÍNGUE", + "translate.glossary.noGlossaryAvailable": "Nenhum glossário disponível", + "translate.glossary.filterByLang": "Filtrar por idioma", + "translate.glossary.active": "Ativo", + "translate.glossary.inactive": "Inativo", + "translate.glossary.availableTemplates": "Modelos disponíveis", + "translate.glossary.importing": "Importando...", + "translate.glossary.imported": "(Importado)", + "translate.glossary.noGlossaryForSource": "Nenhum glossário ou modelo para o idioma de origem", + "translate.glossary.createGlossary": "Criar um glossário", + "translate.glossary.showAll": "Mostrar todos os glossários", + "translate.glossary.activePreview": "Pré-visualização de correspondências ativas:", + "translate.glossary.total": "no total", + "translate.glossary.moreTerms": "termos adicionais", + "translate.glossary.noTerms": "Nenhum termo neste glossário.", + "translate.glossary.sourceTerm": "Termo de origem", + "translate.glossary.translation": "Tradução", + "translate.glossary.addTerm": "Adicionar termo", + "translate.glossary.disabledMode": "Motor neutro sem glossário aplicado", + "translate.glossary.addTermError": "Erro ao adicionar o termo", + "translate.glossary.networkError": "Erro de rede", + "translate.glossary.importFailed": "Falha na importação ({status})", + "translate.glossary.helpText": "O glossário força a tradução precisa de termos. Escolha um glossário cujo idioma de origem corresponda ao idioma original do seu documento.", + "translate.glossary.sourceWarning": "Atenção: Este glossário usa o idioma de origem", + "translate.glossary.sourceWarningBut": "mas o seu documento está configurado em", + "translate.glossary.targetWarning": "Incompatibilidade de destino: Este glossário foi projetado para traduzir para", + "translate.glossary.targetWarningBut": "mas o seu documento tem como destino", + "translate.glossary.targetWarningEnd": "Os termos podem não ser relevantes.", + "translate.header.processing": "Processamento em curso", + "translate.header.aiActive": "Análise IA ativa", + "translate.header.aiActiveDesc": "O seu layout está a ser preservado pelo nosso motor contextual.", + "translate.header.completed": "Concluído", + "translate.header.completedTitle": "Tradução concluída", + "translate.header.proSpace": "Espaço Pro", + "translate.header.translateDoc": "Traduzir um documento", + "translate.header.translateDocDesc": "Mantenha o layout original com o nosso motor de tradução de ultra-alta fidelidade.", + "translate.upload.nativeFormat": "Formato nativo", + "translate.fileType.word": "Word (.docx)", + "translate.fileType.excel": "Excel (.xlsx)", + "translate.fileType.slides": "Slides (.pptx)", + "translate.fileType.pdf": "PDF (.pdf)", + "translate.startTranslation": "Iniciar tradução", + "translate.submit": "A enviar…", + "translate.chooseTargetLang": "Por favor, escolha um idioma de destino", + "translate.pleaseLoadFile": "Por favor, carregue um ficheiro primeiro", + "translate.contextEngineActive": "Motor contextual ativo", + "translate.phase1": "Fase 1: Inicialização", + "translate.phase2": "Fase 2: Reconstrução contextual", + "translate.stat.segments": "segmentos", + "translate.stat.precision": "precisão", + "translate.stat.speedLabel": "velocidade", + "translate.stat.turbo": "Turbo", + "translate.stat.time": "tempo", + "translate.complete.masterQuality": "✓ Qualidade mestre", + "translate.download": "Baixar", + "translate.newTranslation": "+ Nova tradução", + "translate.failedTitle": "Erro de tradução", + "translate.retry": "Tentar novamente", + "translate.uploadAnother": "Carregar outro ficheiro", + "translate.monitor": "Monitor IA", + "translate.summary": "Resumo", + "translate.cancelProcess": "⟳ Cancelar o processo", + "translate.layoutIntegrity": "Integridade do layout", + "translate.secureHundred": "100% SEGURO", + "translate.okHundred": "100% OK", + "translate.preserveLayout": "Manter layout", + "translate.preserveLayoutDesc": "Manter o layout", + "translate.textOnly": "Apenas texto", + "translate.textOnlyDesc": "Tradução rápida apenas do texto", + "translate.unavailableStandard": "Indisponível no modo Padrão (apenas IA)" +} diff --git a/frontend/src/lib/i18n/messages/pt/translateComplete.json b/frontend/src/lib/i18n/messages/pt/translateComplete.json new file mode 100644 index 0000000..9c23f7e --- /dev/null +++ b/frontend/src/lib/i18n/messages/pt/translateComplete.json @@ -0,0 +1,6 @@ +{ + "translateComplete.highQuality": "Alta qualidade", + "translateComplete.segments": "Segmentos", + "translateComplete.characters": "Caracteres", + "translateComplete.confidence": "Confiança" +} diff --git a/frontend/src/lib/i18n/messages/ru/admin.json b/frontend/src/lib/i18n/messages/ru/admin.json new file mode 100644 index 0000000..5ea9122 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/admin.json @@ -0,0 +1,48 @@ +{ + "admin.login.title": "Администрирование", + "admin.login.required": "Требуется вход", + "admin.login.password": "Пароль администратора", + "admin.login.connecting": "Подключение...", + "admin.login.access": "Войти в панель администратора", + "admin.login.restricted": "Доступ ограничен администраторами", + "admin.layout.checking": "Проверка аутентификации...", + "admin.dashboard.title": "Панель администратора", + "admin.dashboard.subtitle": "Панель управления администратора", + "admin.dashboard.refresh": "Обновить", + "admin.dashboard.refreshTooltip": "Обновить данные панели", + "admin.dashboard.config": "Конфигурация системы", + "admin.dashboard.maxFileSize": "Макс. размер файла:", + "admin.dashboard.translationService": "Служба перевода:", + "admin.dashboard.formats": "Форматы:", + "admin.nav.dashboard": "Dashboard", + "admin.nav.users": "Пользователи", + "admin.nav.pricing": "Цены и Stripe", + "admin.nav.providers": "Провайдеры", + "admin.nav.system": "Система", + "admin.nav.logs": "Журналы", + "admin.users.title": "Управление пользователями", + "admin.users.subtitle": "Просмотр и управление учётными записями", + "admin.users.planUpdated": "План обновлён", + "admin.users.planChanged": "План успешно изменён на \\\"{plan}\\\".", + "admin.users.unknownError": "Неизвестная ошибка", + "admin.users.error": "Ошибка", + "admin.users.planUpdateError": "Не удалось обновить план: {message}", + "admin.users.noKeys": "Нет ключей", + "admin.users.noKeysDesc": "У этого пользователя нет активных ключей API.", + "admin.users.keysRevoked": "Ключи отозваны", + "admin.users.keysRevokedDesc": "{count} ключ(ей) API успешно отозвано.", + "admin.users.revokeError": "Не удалось отозвать ключи: {message}", + "admin.users.retry": "Повторить", + "admin.system.title": "Система", + "admin.system.subtitle": "Мониторинг состояния системы и управление ресурсами", + "admin.system.quotas": "Квоты переводов", + "admin.system.resetQuotas": "Сбросить месячные квоты", + "admin.system.resetting": "Сброс...", + "admin.system.reset": "Сбросить", + "admin.system.allOperational": "Все системы работают", + "admin.system.issuesDetected": "Обнаружены проблемы в системе", + "admin.system.waitingData": "Ожидание данных...", + "admin.system.purging": "Очистка...", + "admin.system.clean": "Очистить", + "admin.system.purge": "Очистить" +} diff --git a/frontend/src/lib/i18n/messages/ru/apiKeys.json b/frontend/src/lib/i18n/messages/ru/apiKeys.json new file mode 100644 index 0000000..f917eae --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/apiKeys.json @@ -0,0 +1,72 @@ +{ + "apiKeys.webhook.title": "Intégration Webhook", + "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", + "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", + "apiKeys.webhook.codeParam": "webhook_url", + "apiKeys.title": "API-ключи", + "apiKeys.subtitle": "Управляйте API-ключами для программного доступа к API перевода.", + "apiKeys.loading": "Загрузка...", + "apiKeys.sectionTitle": "API и автоматизация", + "apiKeys.sectionDesc": "Генерируйте и управляйте API-ключами для автоматизации рабочих процессов", + "apiKeys.keysUsed": "{total} из {max} ключей использовано", + "apiKeys.maxReached": "Достигнуто максимальное количество ключей. Отзовите ключ, чтобы создать новый.", + "apiKeys.canGenerate": "Вы можете создать ещё {count} ключ", + "apiKeys.canGeneratePlural": "Вы можете создать ещё {count} ключей", + "apiKeys.generateNew": "Создать новый ключ", + "apiKeys.keyRevoked": "Ключ отозван", + "apiKeys.keyRevokedDesc": "API-ключ успешно отозван.", + "apiKeys.keyNotFound": "Ключ не найден", + "apiKeys.keyNotFoundDesc": "API-ключ больше не существует. Возможно, он уже был отозван.", + "apiKeys.error": "Ошибка", + "apiKeys.revokeError": "Не удалось отозвать API-ключ. Попробуйте снова.", + "apiKeys.limitReached": "Лимит достигнут", + "apiKeys.limitReachedDesc": "Вы достигли максимума в 10 API-ключей. Отзовите существующий ключ, чтобы создать новый.", + "apiKeys.proRequired": "Требуется тариф Pro", + "apiKeys.proRequiredDesc": "API-ключи — функция тарифа Pro. Пожалуйста, повысьте свой тариф.", + "apiKeys.generateError": "Не удалось сгенерировать API-ключ. Попробуйте снова.", + "apiKeys.upgrade.title": "API-ключи", + "apiKeys.upgrade.subtitle": "Автоматизируйте переводы с помощью доступа к API", + "apiKeys.upgrade.feat1": "Неограниченное количество API-ключей", + "apiKeys.upgrade.feat2": "Автоматизация перевода документов", + "apiKeys.upgrade.feat3": "Уведомления через вебхуки", + "apiKeys.upgrade.feat4": "Режимы перевода LLM", + "apiKeys.upgrade.proFeature": "API-ключи — функция тарифа {pro}. Повысьте тариф, чтобы разблокировать автоматизацию API.", + "apiKeys.upgrade.pro": "Pro", + "apiKeys.upgrade.cta": "Перейти на Pro", + "apiKeys.dialog.maxTitle": "Достигнуто максимальное количество ключей", + "apiKeys.dialog.maxDesc": "Вы достигли максимума в 10 API-ключей. Отзовите существующий ключ перед созданием нового.", + "apiKeys.dialog.close": "Закрыть", + "apiKeys.dialog.generated": "API-ключ создан!", + "apiKeys.dialog.generatedDesc": "Ваш новый API-ключ создан. Скопируйте его сейчас — он больше не будет показан.", + "apiKeys.dialog.important": "Важно:", + "apiKeys.dialog.importantDesc": "Это единственный раз, когда вы видите этот ключ. Храните его в безопасности.", + "apiKeys.dialog.apiKey": "API-ключ", + "apiKeys.dialog.name": "Имя:", + "apiKeys.dialog.done": "Готово", + "apiKeys.dialog.copied": "Я скопировал ключ", + "apiKeys.dialog.generateTitle": "Создать новый API-ключ", + "apiKeys.dialog.generateDesc": "Создайте новый API-ключ для программного доступа к API перевода.", + "apiKeys.dialog.keyName": "Имя ключа (необязательно)", + "apiKeys.dialog.keyNamePlaceholder": "напр. Продакшен, Стегинг", + "apiKeys.dialog.keyNameHint": "Описательное имя для идентификации ключа в будущем.", + "apiKeys.dialog.nameTooLong": "Имя должно содержать не более {max} символов", + "apiKeys.dialog.nameInvalid": "Имя может содержать только буквы, цифры, пробелы, дефисы и подчёркивания", + "apiKeys.dialog.cancel": "Отмена", + "apiKeys.dialog.generating": "Генерация...", + "apiKeys.dialog.generate": "Создать ключ", + "apiKeys.table.name": "Имя", + "apiKeys.table.prefix": "Префикс", + "apiKeys.table.created": "Создан", + "apiKeys.table.lastUsed": "Последнее использование", + "apiKeys.table.never": "Никогда", + "apiKeys.table.actions": "Действия", + "apiKeys.table.revoke": "Отозвать", + "apiKeys.table.copyPrefix": "Копировать префикс ключа", + "apiKeys.table.revokeKey": "Отозвать ключ", + "apiKeys.revokeDialog.title": "Отзыв API-ключа", + "apiKeys.revokeDialog.desc": "Вы уверены, что хотите отозвать ключ \\\"{name}\\\"? Это действие нельзя отменить.", + "apiKeys.revokeDialog.confirm": "Да, отозвать", + "apiKeys.revokeDialog.cancel": "Отмена", + "apiKeys.noKeysGenerated": "Ключи не созданы", + "apiKeys.copied": "Скопировано!" +} diff --git a/frontend/src/lib/i18n/messages/ru/auth.json b/frontend/src/lib/i18n/messages/ru/auth.json new file mode 100644 index 0000000..b300370 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/auth.json @@ -0,0 +1,3 @@ +{ + "auth.brandName": "Wordly" +} diff --git a/frontend/src/lib/i18n/messages/ru/checkout.json b/frontend/src/lib/i18n/messages/ru/checkout.json new file mode 100644 index 0000000..2185c36 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/checkout.json @@ -0,0 +1,12 @@ +{ + "checkout.activating": "Активация…", + "checkout.activatingDesc": "Обновляем вашу подписку, подождите.", + "checkout.paymentConfirmed": "Платёж подтверждён!", + "checkout.subscriptionActivated": "Подписка активирована!", + "checkout.planActivated": "Тариф {plan} активирован!", + "checkout.redirectingToProfile": "Перенаправление в профиль…", + "checkout.paymentReceived": "Платёж получен", + "checkout.redirecting": "Перенаправление…", + "checkout.syncError": "Ошибка синхронизации", + "checkout.networkError": "Ошибка сети. Платёж подтверждён — перезагрузите профиль." +} diff --git a/frontend/src/lib/i18n/messages/ru/common.json b/frontend/src/lib/i18n/messages/ru/common.json new file mode 100644 index 0000000..cef7554 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/common.json @@ -0,0 +1,4 @@ +{ + "common.loading": "Загрузка...", + "common.backToHome": "Вернуться на главную" +} diff --git a/frontend/src/lib/i18n/messages/ru/context.json b/frontend/src/lib/i18n/messages/ru/context.json new file mode 100644 index 0000000..5f0dfe2 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/context.json @@ -0,0 +1,25 @@ +{ + "context.proTitle": "Функция Pro", + "context.proDesc": "Контекст и профессиональные глоссарии доступны на тарифах Pro, Business и Enterprise. Они обеспечивают более точные переводы благодаря инструкциям и словарю, специфичному для вашей области.", + "context.viewPlans": "Посмотреть тарифы", + "context.title": "Контекст и глоссарий", + "context.subtitle": "Улучшите качество перевода с помощью инструкций и словаря, специфичного для вашей области.", + "context.presets.title": "Профессиональные глоссарии", + "context.presets.desc": "Загрузите полный глоссарий с инструкциями и специализированной терминологией", + "context.instructions.title": "Инструкции контекста", + "context.instructions.desc": "Инструкции, которым ИИ будет следовать при переводе", + "context.instructions.placeholder": "Напр.: Вы переводите техническую документацию по HVAC. Используйте точную инженерную терминологию...", + "context.glossary.title": "Технический глоссарий", + "context.glossary.desc": "Формат: источник=цель (по одному на строку). Глоссарии, загруженные через пресет, можно редактировать.", + "context.glossary.terms": "терминов в глоссарии", + "context.clearAll": "Очистить всё", + "context.saving": "Сохранение...", + "context.save": "Сохранить", + "context.presets.createGlossary": "Создать глоссарий", + "context.presets.created": "Глоссарий создан", + "context.presets.createdDesc": "Глоссарий \\\"{name}\\\" создан с {count} терминами.", + "context.presets.hint": "Нажмите на пресет, чтобы создать глоссарий с предметными терминами. Управляйте глоссариями в разделе Глоссарии.", + "context.glossary.manage": "Управлять глоссариями", + "context.saved": "Сохранено", + "context.savedDesc": "Ваши контекстные инструкции сохранены." +} diff --git a/frontend/src/lib/i18n/messages/ru/cookieConsent.json b/frontend/src/lib/i18n/messages/ru/cookieConsent.json new file mode 100644 index 0000000..bb88de6 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/cookieConsent.json @@ -0,0 +1,7 @@ +{ + "cookieConsent.title": "Файлы cookie в Wordly", + "cookieConsent.description": "Мы используем essential файлы cookie для работы приложения (сессия, безопасность, язык). С вашего разрешения мы также используем необязательные файлы cookie для измерения трафика и улучшения продукта.", + "cookieConsent.acceptAll": "Принять все", + "cookieConsent.essentialOnly": "Только необходимые", + "cookieConsent.learnMore": "Подробнее" +} diff --git a/frontend/src/lib/i18n/messages/ru/dashboard.json b/frontend/src/lib/i18n/messages/ru/dashboard.json new file mode 100644 index 0000000..71cd9c0 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/dashboard.json @@ -0,0 +1,111 @@ +{ + "dashboard.nav.translate": "Перевести", + "dashboard.nav.profile": "Мой профиль", + "dashboard.nav.settings": "Настройки", + "dashboard.nav.context": "Контекст", + "dashboard.nav.services": "Сервисы", + "dashboard.nav.apiKeys": "API-ключи", + "dashboard.nav.glossaries": "Глоссарии", + "dashboard.header.title": "Панель управления", + "dashboard.header.subtitle": "Управляйте своими переводами", + "dashboard.header.toggleMenu": "Меню", + "dashboard.header.profileTitle": "Мой профиль", + "dashboard.sidebar.theme": "Тема", + "dashboard.sidebar.signOut": "Выйти", + "dashboard.sidebar.backHome": "Вернуться на главную", + "dashboard.sidebar.upgradeToPro": "Обновить до Pro →", + "dashboard.translate.pageTitle": "Перевести документ", + "dashboard.translate.pageSubtitle": "Импортируйте файл и выберите целевой язык", + "dashboard.translate.errorNotificationTitle": "Ошибка", + "dashboard.translate.dropzone.uploadAria": "Зона перетаскивания файлов", + "dashboard.translate.dropzone.title": "Перетащите файл сюда", + "dashboard.translate.dropzone.subtitle": "или нажмите, чтобы выбрать (DOCX, XLSX, PPTX, PDF)", + "dashboard.translate.dropzone.replaceFile": "Заменить файл", + "dashboard.translate.language.source": "Исходный язык", + "dashboard.translate.language.target": "Целевой язык", + "dashboard.translate.language.loading": "Загрузка языков…", + "dashboard.translate.language.autoDetect": "Автоопределение", + "dashboard.translate.language.selectPlaceholder": "Выбрать…", + "dashboard.translate.language.loadErrorPrefix": "Ошибка загрузки языков", + "dashboard.translate.provider.loading": "Загрузка провайдеров…", + "dashboard.translate.provider.noneConfigured": "Провайдеры не настроены", + "dashboard.translate.provider.modelTitle": "Модель", + "dashboard.translate.provider.sectionTitle": "Провайдер", + "dashboard.translate.provider.llmDivider": "ИИ · Контекстный", + "dashboard.translate.provider.llmDividerPro": "ИИ · Контекстный (Pro)", + "dashboard.translate.provider.upgrade": "Обновить до Pro", + "dashboard.translate.provider.upgradeSuffix": "чтобы разблокировать ИИ-перевод", + "dashboard.translate.trust.zeroRetention": "Без хранения", + "dashboard.translate.trust.deletedAfter": "Файлы удаляются после обработки", + "dashboard.translate.actions.uploading": "Загрузка…", + "dashboard.translate.actions.translate": "Перевести", + "dashboard.translate.actions.filePrefix": "Файл: ", + "dashboard.translate.actions.cancel": "Отмена", + "dashboard.translate.actions.tryAgain": "Повторить", + "dashboard.translate.steps.uploading": "Загрузка файла…", + "dashboard.translate.steps.starting": "Запуск перевода…", + "dashboard.translate.complete.title": "Перевод завершён!", + "dashboard.translate.complete.descNamed": "Ваш файл {name} успешно переведён.", + "dashboard.translate.complete.descGeneric": "Ваш файл успешно переведён.", + "dashboard.translate.complete.downloading": "Скачивание…", + "dashboard.translate.complete.download": "Скачать", + "dashboard.translate.complete.newTranslation": "Новый перевод", + "dashboard.translate.complete.toastOkTitle": "Успешно", + "dashboard.translate.complete.toastOkDesc": "{name} успешно загружен.", + "dashboard.translate.complete.toastFailTitle": "Ошибка", + "dashboard.translate.complete.toastFailDesc": "Перевод не удался. Пожалуйста, попробуйте снова.", + "dashboard.translate.sourceDocument": "Исходный документ", + "dashboard.translate.configuration": "Настройки", + "dashboard.translate.translating": "Перевод выполняется", + "dashboard.translate.liveMonitor": "Мониторинг", + "dashboard.translate.summary": "Сводка", + "dashboard.translate.engine": "Движок", + "dashboard.translate.confidence": "Достоверность", + "dashboard.translate.cancel": "Отмена", + "dashboard.translate.segments": "Сегменты", + "dashboard.translate.characters": "Символы", + "dashboard.translate.elapsed": "Прошло", + "dashboard.translate.segPerMin": "Сег/мин", + "dashboard.translate.highQuality": "Высокое качество", + "dashboard.translate.quality": "Качество", + "dashboard.translate.completed": "Перевод завершён", + "dashboard.translate.replace": "Заменить", + "dashboard.translate.pdfMode.title": "Режим перевода PDF", + "dashboard.translate.pdfMode.preserveLayout": "Сохранить вёрстку", + "dashboard.translate.pdfMode.textOnly": "Только текст", + "dashboard.translate.pdfMode.preserveLayoutDesc": "Сохраняет изображения, таблицы и форматирование. Лучше для простых PDF.", + "dashboard.translate.pdfMode.textOnlyDesc": "Идеальный перевод всего текста. Чистый результат без проблем с вёрсткой.", + "dashboard.translate.pipeline.upload": "Загрузка", + "dashboard.translate.pipeline.analyze": "Анализ", + "dashboard.translate.pipeline.translate": "Перевод", + "dashboard.translate.pipeline.rebuild": "Восстановление", + "dashboard.translate.pipeline.finalize": "Завершение", + "dashboard.translate.progress.processingFallback": "Обработка…", + "dashboard.translate.progress.connectionLost": "Соединение потеряно. Повторная попытка…", + "dashboard.translate.progress.failedTitle": "Перевод не удался", + "dashboard.translate.error.unexpected": "Произошла непредвиденная ошибка. Попробуйте снова.", + "dashboard.translate.error.noResult": "Перевод не дал результатов. Убедитесь, что документ содержит текст, и попробуйте снова или выберите другой движок.", + "dashboard.translate.error.apiKey": "Недействительный или отсутствующий API-ключ. Обратитесь к администратору для настройки ключей.", + "dashboard.translate.error.quota": "Лимит использования достигнут. Попробуйте снова через несколько минут или выберите другой движок.", + "dashboard.translate.error.timeout": "Время соединения с сервисом перевода истекло. Проверьте сеть и попробуйте снова.", + "dashboard.translate.error.sessionExpired": "Сессия истекла. Нажмите «Повторить» для перезапуска перевода.", + "dashboard.translate.error.empty": "Документ пуст или не содержит переводимого текста (сканированный PDF?).", + "dashboard.translate.error.unsupported": "Неподдерживаемый формат файла или повреждённый файл.", + "dashboard.translate.error.connection": "Соединение потеряно. Проверьте сеть и попробуйте снова.", + "dashboard.translate.error.generic": "Перевод не удался: {detail}", + "dashboard.translate.error.title": "Перевод не удался", + "dashboard.translate.retry": "Повторить перевод", + "dashboard.translate.newFile": "Новый файл", + "dashboard.translate.modeAI": "Режим ИИ", + "dashboard.translate.modeClassic": "Классический режим", + "dashboard.translate.glossaryLLMHint": "Глоссарии доступны в режиме ИИ", + "dashboard.translate.submitting": "Отправка...", + "dashboard.translate.submit": "Начать перевод", + "dashboard.translate.noFile": "Сначала загрузите файл", + "dashboard.translate.noTargetLang": "Выберите целевой язык", + "dashboard.topbar.interfaceLabel": "Интерфейс перевода", + "dashboard.topbar.premiumAccess": "Премиум-доступ", + "dashboard.checkoutSyncError": "Ошибка синхронизации платежа.", + "dashboard.networkRefresh": "Ошибка сети. Обновите страницу.", + "dashboard.continueToTranslate": "Перейти к переводу" +} diff --git a/frontend/src/lib/i18n/messages/ru/fileUploader.json b/frontend/src/lib/i18n/messages/ru/fileUploader.json new file mode 100644 index 0000000..87d4c64 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/fileUploader.json @@ -0,0 +1,31 @@ +{ + "fileUploader.uploadDocument": "Загрузить документ", + "fileUploader.uploadDesc": "Перетащите или нажмите, чтобы выбрать файл (Excel, Word, PowerPoint)", + "fileUploader.dropHere": "Перетащите файл сюда…", + "fileUploader.dragAndDrop": "Перетащите документ сюда", + "fileUploader.orClickBrowse": "или нажмите, чтобы выбрать", + "fileUploader.preview": "Предпросмотр", + "fileUploader.translationOptions": "Параметры перевода", + "fileUploader.configureSettings": "Настройте параметры перевода", + "fileUploader.targetLanguage": "Целевой язык", + "fileUploader.selectLanguage": "Выберите язык", + "fileUploader.translationProvider": "Поставщик перевода", + "fileUploader.selectProvider": "Выберите поставщика", + "fileUploader.advancedOptions": "Расширенные параметры", + "fileUploader.translateImages": "Переводить изображения", + "fileUploader.translating": "Перевод…", + "fileUploader.translateDocument": "Перевести документ", + "fileUploader.processing": "Обработка…", + "fileUploader.translationError": "Ошибка перевода", + "fileUploader.translationComplete": "Перевод завершён!", + "fileUploader.translationCompleteDesc": "Ваш документ успешно переведён с сохранением форматирования.", + "fileUploader.download": "Скачать переведённый документ", + "fileUploader.webgpuUnsupported": "WebGPU не поддерживается в этом браузере. Используйте Chrome 113+ или Edge 113+.", + "fileUploader.webllmNotLoaded": "Модель WebLLM не загружена. Перейдите в Настройки > Службы перевода, чтобы загрузить модель.", + "fileUploader.extracting": "Извлечение текстов из документа…", + "fileUploader.noTranslatable": "В документе не найден переводимый текст", + "fileUploader.foundTexts": "Найдено {count} текстов для перевода", + "fileUploader.translatingItem": "Перевод {current}/{total}: «{preview}»", + "fileUploader.reconstructing": "Восстановление документа…", + "fileUploader.translatingLocally": "Локальный перевод с WebLLM…" +} diff --git a/frontend/src/lib/i18n/messages/ru/forgotPassword.json b/frontend/src/lib/i18n/messages/ru/forgotPassword.json new file mode 100644 index 0000000..0ac67c8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/forgotPassword.json @@ -0,0 +1,14 @@ +{ + "forgotPassword.enterEmail": "Please enter your email address", + "forgotPassword.error": "An error occurred", + "forgotPassword.title": "Forgot Password", + "forgotPassword.checkEmail": "Check your inbox", + "forgotPassword.subtitle": "Enter your email to receive a reset link", + "forgotPassword.sentMessage": "If an account exists with this address, a reset email has been sent.", + "forgotPassword.emailLabel": "Email address", + "forgotPassword.emailPlaceholder": "you@example.com", + "forgotPassword.sending": "Sending...", + "forgotPassword.sendLink": "Send reset link", + "forgotPassword.backToLogin": "Back to login", + "forgotPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/ru/glossaries.json b/frontend/src/lib/i18n/messages/ru/glossaries.json new file mode 100644 index 0000000..4f46bbd --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/glossaries.json @@ -0,0 +1,189 @@ +{ + "glossaries.yourGlossaries": "Ваши глоссарии", + "glossaries.title": "Глоссарии и контекст", + "glossaries.description": "Управляйте глоссариями и контекстными инструкциями для более точных переводов.", + "glossaries.createNew": "Создать новый", + "glossaries.empty": "Глоссариев пока нет", + "glossaries.emptyDesc": "Создайте первый глоссарий или загрузите профессиональный пресет выше", + "glossaries.defineTerms": "терминов", + "glossaries.aboutTitle": "О глоссариях", + "glossaries.aboutDesc": "Глоссарии позволяют определить точные переводы для конкретных терминов. При переводе термины из глоссария обеспечивают последовательные и точные переводы.", + "glossaries.aboutFormat": "Каждый термин имеет исходное слово и переводы на несколько языков. Выберите глоссарий на странице перевода, чтобы применить его.", + "glossaries.toast.created": "Глоссарий создан", + "glossaries.toast.createdDesc": "Глоссарий \\\"{name}\\\" создан.", + "glossaries.toast.imported": "Глоссарий импортирован", + "glossaries.toast.importedDesc": "Глоссарий \\\"{name}\\\" импортирован.", + "glossaries.toast.updated": "Глоссарий обновлён", + "glossaries.toast.updatedDesc": "Глоссарий \\\"{name}\\\" обновлён.", + "glossaries.toast.deleted": "Глоссарий удалён", + "glossaries.toast.deletedDesc": "Глоссарий удалён.", + "glossaries.toast.error": "Ошибка", + "glossaries.toast.errorCreate": "Не удалось создать глоссарий", + "glossaries.toast.errorImport": "Не удалось импортировать глоссарий", + "glossaries.toast.errorUpdate": "Не удалось обновить глоссарий", + "glossaries.toast.errorDelete": "Не удалось удалить глоссарий", + "glossaries.dialog.title": "Новый глоссарий", + "glossaries.dialog.description": "Создайте глоссарий для ваших переводов", + "glossaries.dialog.nameLabel": "Название", + "glossaries.dialog.namePlaceholder": "Мой глоссарий", + "glossaries.dialog.tabTemplates": "Шаблоны", + "glossaries.dialog.tabFile": "Файл", + "glossaries.dialog.tabManual": "Вручную", + "glossaries.dialog.cancel": "Отмена", + "glossaries.dialog.creating": "Создание…", + "glossaries.dialog.importing": "Импорт…", + "glossaries.dialog.importBtn": "Импортировать", + "glossaries.dialog.selectPrompt": "Выбрать", + "glossaries.dialog.createBtn": "Создать", + "glossaries.dialog.createEmpty": "Создать пустой", + "glossaries.dialog.terms": "терминов", + "glossaries.dialog.templatesDesc": "Выберите готовый шаблон", + "glossaries.dialog.templatesEmpty": "Нет доступных шаблонов", + "glossaries.dialog.dropTitle": "Перетащите CSV-файл сюда", + "glossaries.dialog.dropOr": "или", + "glossaries.dialog.dropFormats": "CSV, TSV, TXT", + "glossaries.termEditor.addTerm": "Добавить термин", + "glossaries.termEditor.maxReached": "Достигнуто максимум {max} терминов в глоссарии.", + "glossaries.dialog.formatTitle": "Формат", + "glossaries.dialog.formatDesc": "источник,цель (по одной на строку)", + "glossaries.dialog.formatNote": "Первая строка пропускается при обнаружении заголовка", + "glossaries.dialog.errorFormat": "Неподдерживаемый формат", + "glossaries.dialog.errorSize": "Файл слишком большой", + "glossaries.dialog.errorEmpty": "Пустой файл", + "glossaries.dialog.errorRead": "Ошибка чтения", + "glossaries.dialog.parsing": "Обработка…", + "glossaries.dialog.termsImported": "терминов импортировано", + "glossaries.dialog.changeFile": "Изменить файл", + "glossaries.dialog.retry": "Повторить", + "glossaries.edit.title": "Modifier le glossaire", + "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", + "glossaries.edit.nameLabel": "Nom du glossaire", + "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", + "glossaries.edit.sourceLang": "Langue source", + "glossaries.edit.targetLang": "Langue cible", + "glossaries.edit.termsLabel": "Termes ({count} valides)", + "glossaries.edit.exportCsv": "Exporter CSV", + "glossaries.edit.importCsv": "Importer CSV", + "glossaries.edit.cancel": "Annuler", + "glossaries.edit.saving": "Enregistrement...", + "glossaries.edit.saveChanges": "Enregistrer les modifications", + "glossaries.edit.importFailedTitle": "Échec de l'importation", + "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", + "glossaries.edit.importSuccessTitle": "Importation réussie", + "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", + "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", + "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", + "glossaries.delete.title": "Supprimer le glossaire", + "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", + "glossaries.delete.warning": "Cette action est irréversible", + "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", + "glossaries.delete.cancel": "Annuler", + "glossaries.delete.deleting": "Suppression...", + "glossaries.delete.deleteBtn": "Supprimer", + "glossaries.upgrade.title": "Glossaires", + "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", + "glossaries.upgrade.feature1": "Créez plusieurs glossaires", + "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", + "glossaries.upgrade.feature3": "Importez/exportez via CSV", + "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", + "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", + "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", + "glossaries.upgrade.proLabel": "Pro", + "glossaries.upgrade.upgradeBtn": "Passer à Pro", + "glossaries.loading": "Chargement...", + "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", + "glossaries.howItWorks.step1Title": "Configurez ici", + "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", + "glossaries.howItWorks.step2Title": "Activez dans Traduire", + "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", + "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", + "glossaries.howItWorks.goToTranslate": "Aller à Traduire", + "glossaries.status.unsaved": "Non enregistré", + "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", + "glossaries.status.inactive": "Inactif", + "glossaries.instructions.whatForBold": "À quoi ça sert ?", + "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", + "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", + "glossaries.instructions.charCount": "{count} caractères", + "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", + "glossaries.instructions.clearAll": "Tout effacer", + "glossaries.instructions.saving": "Enregistrement…", + "glossaries.instructions.saved": "Enregistré", + "glossaries.presets.whatForBold": "À quoi ça sert ?", + "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", + "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", + "glossaries.presets.creating": "Création…", + "glossaries.presets.alreadyImported": "Déjà importé", + "glossaries.presets.it.title": "IT / Logiciel", + "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", + "glossaries.presets.legal.title": "Juridique / Contrats", + "glossaries.presets.legal.desc": "Droit des affaires, contentieux", + "glossaries.presets.medical.title": "Médical / Santé", + "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", + "glossaries.presets.finance.title": "Finance / Comptabilité", + "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", + "glossaries.presets.marketing.title": "Marketing / Publicité", + "glossaries.presets.marketing.desc": "Digital, branding, analytics", + "glossaries.presets.hr.title": "RH / Ressources Humaines", + "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", + "glossaries.presets.scientific.title": "Scientifique / Recherche", + "glossaries.presets.scientific.desc": "Publications, thèses, articles", + "glossaries.presets.ecommerce.title": "E-commerce / Vente", + "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", + "glossaries.grid.title": "Vos", + "glossaries.grid.titleHighlight": "glossaires", + "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", + "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", + "glossaries.grid.activeTranslation": "Traduction active :", + "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", + "glossaries.badge.compatible": "Compatible", + "glossaries.badge.otherTarget": "Autre cible", + "glossaries.card.editTerms": "Modifier les termes", + "glossaries.card.created": "Создано", + "glossaries.card.term": "термин", + "glossaries.card.delete": "Supprimer", + "glossaries.grid.searchPlaceholder": "Search a glossary…", + "glossaries.grid.noResults": "No results for this search.", + "glossaries.detail.backToList": "Back to glossaries", + "glossaries.detail.save": "Save", + "glossaries.detail.savedTitle": "Saved", + "glossaries.detail.savedDesc": "The glossary has been updated.", + "glossaries.detail.settingsTitle": "Settings", + "glossaries.detail.sourceLang": "Source language", + "glossaries.detail.targetLang": "Target language", + "glossaries.detail.termsTitle": "Terms", + "glossaries.detail.terms": "terms", + "glossaries.detail.searchTerms": "Filter…", + "glossaries.detail.noTerms": "No terms yet.", + "glossaries.detail.addFirstTerm": "Add the first term", + "glossaries.detail.addTerm": "Add a term", + "glossaries.detail.maxReached": "Maximum limit reached", + "glossaries.detail.source": "Source", + "glossaries.detail.target": "Target", + "glossaries.detail.sourcePlaceholder": "source term", + "glossaries.detail.targetPlaceholder": "target term", + "glossaries.detail.csvTitle": "CSV", + "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", + "glossaries.detail.export": "Export", + "glossaries.detail.import": "Import", + "glossaries.detail.dangerTitle": "Danger zone", + "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", + "glossaries.detail.deleteGlossary": "Delete this glossary", + "glossaries.detail.confirmDelete": "Confirm deletion?", + "glossaries.detail.confirm": "Confirm", + "glossaries.detail.cancel": "Cancel", + "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", + "glossaries.detail.sourceLocked": "fixed", + "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", + "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", + "glossaries.detail.notFoundTitle": "Glossary not found", + "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", + "glossaries.detail.maxTermsTitle": "Limit reached", + "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", + "glossaries.detail.importEmptyTitle": "Empty file", + "glossaries.detail.importEmptyDesc": "No terms detected in this file.", + "glossaries.detail.importedTitle": "Imported", + "glossaries.detail.importedDesc": "{count} terms imported.", + "glossaries.detail.importErrorTitle": "Read error", + "glossaries.detail.importErrorDesc": "Unable to read the file." +} diff --git a/frontend/src/lib/i18n/messages/ru/index.ts b/frontend/src/lib/i18n/messages/ru/index.ts new file mode 100644 index 0000000..80cfd38 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/index.ts @@ -0,0 +1,60 @@ +// Auto-generated by scripts/generate_i18n_index.py +// Merges all namespace JSON files for locale "ru". + +import admin from "./admin.json"; +import apiKeys from "./apiKeys.json"; +import auth from "./auth.json"; +import checkout from "./checkout.json"; +import common from "./common.json"; +import context from "./context.json"; +import cookieConsent from "./cookieConsent.json"; +import dashboard from "./dashboard.json"; +import fileUploader from "./fileUploader.json"; +import forgotPassword from "./forgotPassword.json"; +import glossaries from "./glossaries.json"; +import landing from "./landing.json"; +import langSelector from "./langSelector.json"; +import layout from "./layout.json"; +import login from "./login.json"; +import memento from "./memento.json"; +import pricing from "./pricing.json"; +import profile from "./profile.json"; +import providerSelector from "./providerSelector.json"; +import providerTheme from "./providerTheme.json"; +import register from "./register.json"; +import resetPassword from "./resetPassword.json"; +import services from "./services.json"; +import settings from "./settings.json"; +import translate from "./translate.json"; +import translateComplete from "./translateComplete.json"; + +const messages: Record = { + ...admin, + ...apiKeys, + ...auth, + ...checkout, + ...common, + ...context, + ...cookieConsent, + ...dashboard, + ...fileUploader, + ...forgotPassword, + ...glossaries, + ...landing, + ...langSelector, + ...layout, + ...login, + ...memento, + ...pricing, + ...profile, + ...providerSelector, + ...providerTheme, + ...register, + ...resetPassword, + ...services, + ...settings, + ...translate, + ...translateComplete, +}; + +export default messages; diff --git a/frontend/src/lib/i18n/messages/ru/landing.json b/frontend/src/lib/i18n/messages/ru/landing.json new file mode 100644 index 0000000..8a5b68e --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/landing.json @@ -0,0 +1,146 @@ +{ + "landing.nav.why": "Почему мы?", + "landing.nav.formats": "Форматы", + "landing.nav.pricing": "Цены", + "landing.nav.login": "Войти", + "landing.nav.startFree": "Бесплатно", + "landing.hero.tag": "Профессиональный документальный ИИ", + "landing.hero.titleLine1": "Переводите документы.", + "landing.hero.titleLine2": "С идеальным форматированием.", + "landing.hero.description": "Единственный переводчик, который сохраняет SmartArt, диаграммы, оглавления, фигуры и сложные макеты — в точности как в оригинале.", + "landing.hero.ctaMain": "Бесплатно — 2 док./мес.", + "landing.hero.ctaSec": "Смотреть тарифы", + "landing.hero.deleted": "Файлы удаляются через 60 мин.", + "landing.hero.noHidden": "Без скрытых платежей", + "landing.hero.preview": "Предпросмотр перед оплатой", + "landing.hero.formattedOk": "Форматирование ОК", + "landing.hero.aiActive": "ИИ-перевод активен", + "landing.steps.title": "Как это работает?", + "landing.steps.subtitle": "Три шага. Нулевая потеря форматирования.", + "landing.steps.step1.num": "01", + "landing.steps.step1.title": "Загрузите файл", + "landing.steps.step1.desc": "Перетащите документ Excel, Word, PowerPoint или PDF.", + "landing.steps.step2.num": "02", + "landing.steps.step2.title": "Выберите язык и движок", + "landing.steps.step2.desc": "Выберите целевой язык и движок — классический или контекстный ИИ.", + "landing.steps.step3.num": "03", + "landing.steps.step3.title": "Скачайте результат", + "landing.steps.step3.desc": "Получите переведённый документ с форматированием, идентичным оригиналу.", + "landing.features.tag": "Движок ИИ-перевода", + "landing.features.title": "Перевод, который понимает вашу сферу", + "landing.features.description": "Наши ИИ-модели анализируют контекст, уважают вашу терминологию и даже переводят текст внутри изображений.", + "landing.features.context.title": "Отраслевой контекст", + "landing.features.context.desc": "Опишите свою отрасль и получите адаптированный перевод, а не универсальный.", + "landing.features.glossary.title": "Отраслевые глоссарии", + "landing.features.glossary.desc": "Определите свои технические термины. CTA останется «Воздухообрабатывающая установка», а не «Призыв к действию».", + "landing.features.vision.title": "Распознавание изображений", + "landing.features.vision.desc": "Текст, встроенный в изображения, диаграммы и графики, распознаётся и переводится.", + "landing.features.demo.source": "Исходник (FR)", + "landing.features.demo.google": "Google Translate", + "landing.features.demo.ours": "Наш ИИ", + "landing.layout.title": "Ваше форматирование,", + "landing.layout.title2": "идеально сохранено", + "landing.layout.subtitle": "Другие переводчики ломают макет. Мы — нет.", + "landing.layout.p1.title": "SmartArt и диаграммы", + "landing.layout.p1.desc": "Органограммы, блок-схемы, иерархии — всё переведено идентично.", + "landing.layout.p2.title": "Оглавления", + "landing.layout.p2.desc": "Записи оглавления, номера страниц и перекрёстные ссылки обновлены корректно.", + "landing.layout.p3.title": "Диаграммы и графики", + "landing.layout.p3.desc": "Заголовки, подписи осей, легенды и названия серий — всё переведено.", + "landing.layout.p4.title": "Фигуры и текстовые поля", + "landing.layout.p4.desc": "Прямоугольники, скруглённые блоки, выноски — локализованы повсюду.", + "landing.layout.p5.title": "Колонтитулы", + "landing.layout.p5.desc": "Верхние и нижние колонтитулы, а также сноски никогда не пропускаются.", + "landing.layout.p6.title": "130+ языков", + "landing.layout.p6.desc": "Google Переводчик, DeepL и профессиональные ИИ-движки.", + "landing.formats.title": "Любой формат,", + "landing.formats.title2": "любой элемент", + "landing.formats.subtitle": "Мы переводим то, что другие пропускают. Ваш бизнес заслуживает безупречной документации.", + "landing.formats.word.name": "Word", + "landing.formats.word.i1": "Абзацы и заголовки", + "landing.formats.word.i2": "Таблицы и диаграммы", + "landing.formats.word.i3": "Диаграммы SmartArt", + "landing.formats.word.i4": "Оглавление", + "landing.formats.word.i5": "Колонтитулы", + "landing.formats.word.i6": "Фигуры и текстовые поля", + "landing.formats.word.i7": "Сноски и концевые сноски", + "landing.formats.excel.name": "Excel", + "landing.formats.excel.i1": "Значения ячеек", + "landing.formats.excel.i2": "Имена листов", + "landing.formats.excel.i3": "Диаграммы и подписи", + "landing.formats.excel.i4": "Колонтитулы", + "landing.formats.excel.i5": "Объединённые ячейки сохранены", + "landing.formats.pptx.name": "PowerPoint", + "landing.formats.pptx.i1": "Текст слайдов и заметки", + "landing.formats.pptx.i2": "Диаграммы и графики", + "landing.formats.pptx.i3": "Фигуры и текстовые поля", + "landing.formats.pptx.i4": "Макеты образцов", + "landing.formats.pptx.i5": "Анимации сохранены", + "landing.formats.pdf.name": "PDF", + "landing.formats.pdf.i1": "Текстовые PDF", + "landing.formats.pdf.i2": "Макет сохранён", + "landing.formats.pdf.i3": "Изображения на месте", + "landing.formats.pdf.i4": "Таблицы сохранены", + "landing.formats.pdf.i5": "Результат в DOCX или PDF", + "landing.pricing.title": "Простые и честные цены", + "landing.pricing.subtitle": "Что видите — то и платите. Без скрытых платежей.", + "landing.pricing.monthly": "Ежемесячно", + "landing.pricing.annual": "Ежегодно", + "landing.pricing.bestValue": "Самый популярный", + "landing.pricing.month": "/мес.", + "landing.pricing.footer": "Указанная цена — это цена, которую вы платите. Никаких скрытых платежей после перевода.", + "landing.pricing.starter.name": "Starter", + "landing.pricing.starter.desc": "Для частных лиц и небольших проектов", + "landing.pricing.starter.f1": "50 документов / мес.", + "landing.pricing.starter.f2": "До 50 страниц на документ", + "landing.pricing.starter.f3": "Google Переводчик + DeepL", + "landing.pricing.starter.f4": "Файлы до 10 МБ", + "landing.pricing.starter.cta": "Начать", + "landing.pricing.pro.name": "Pro", + "landing.pricing.pro.desc": "Для требовательных профессионалов", + "landing.pricing.pro.f1": "200 документов / мес.", + "landing.pricing.pro.f2": "До 200 страниц на документ", + "landing.pricing.pro.f3": "Перевод на базе ИИ", + "landing.pricing.pro.f4": "Google + DeepL включены", + "landing.pricing.pro.f5": "Пользовательские глоссарии и промпты", + "landing.pricing.pro.f6": "Приоритетная поддержка", + "landing.pricing.pro.cta": "Попробовать Pro", + "landing.pricing.business.name": "Бизнес", + "landing.pricing.business.desc": "Для команд с большими объёмами", + "landing.pricing.business.f1": "1 000 документов / мес.", + "landing.pricing.business.f2": "До 500 страниц на документ", + "landing.pricing.business.f3": "Премиум ИИ (Claude)", + "landing.pricing.business.f4": "Все провайдеры + API", + "landing.pricing.business.f5": "Вебхуки и автоматизация", + "landing.pricing.business.f6": "5 рабочих мест", + "landing.pricing.business.cta": "Связаться с нами", + "landing.cta.title": "Начните переводить за 30 секунд", + "landing.cta.subtitle": "Кредитная карта не требуется. Попробуйте бесплатно прямо сейчас и верните к жизни ваши многоязычные документы.", + "landing.cta.button": "Создать бесплатный аккаунт", + "landing.cta.secure": "Защищено шифрованием AES-256", + "landing.footer.desc": "Эксперт в интеллектуальном переводе документов. Мы сочетаем искусство вёрстки с наукой контекстного ИИ.", + "landing.footer.product": "Продукт", + "landing.footer.resources": "Ресурсы", + "landing.footer.legal": "Правовая информация", + "landing.footer.rights": "© 2026 Wordly.art — Все права защищены.", + "landing.hero.contextEngine": "Обнаружен перевод: Технический термин обслуживания для систем HVAC...", + "landing.hero.liveAnalysis": "Анализ в реальном времени", + "landing.hero.termsDetected": "терминов обнаружено", + "landing.steps.process": "ПРОЦЕСС", + "landing.translate.newProject": "Новый проект", + "landing.translate.title": "Перевести документ", + "landing.translate.subtitle": "Импортируйте файл и выберите целевой язык", + "landing.translate.sourceDocument": "Исходный документ", + "landing.translate.configuration": "Настройки", + "landing.translate.sourceLang": "Исходный язык", + "landing.translate.targetLang": "Целевой язык", + "landing.translate.provider": "Провайдер", + "landing.translate.startTranslation": "Начать перевод", + "landing.translate.zeroRetention": "Нулевое хранение", + "landing.translate.filesDeleted": "Файлы удаляются после обработки", + "landing.translate.dropHere": "Перетащите сюда", + "landing.translate.supportedFormats": "Поддерживаются файлы DOCX, XLSX, PPTX или PDF", + "landing.translate.aiAnalysis": "Активный ИИ-анализ", + "landing.translate.processing": "Обработка", + "landing.translate.preservingLayout": "Ваше форматирование сохраняется" +} diff --git a/frontend/src/lib/i18n/messages/ru/langSelector.json b/frontend/src/lib/i18n/messages/ru/langSelector.json new file mode 100644 index 0000000..825ecda --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/langSelector.json @@ -0,0 +1,7 @@ +{ + "langSelector.search": "Поиск…", + "langSelector.noResults": "Нет результатов", + "langSelector.source": "Источник", + "langSelector.target": "Цель", + "langSelector.swap": "Поменять" +} diff --git a/frontend/src/lib/i18n/messages/ru/layout.json b/frontend/src/lib/i18n/messages/ru/layout.json new file mode 100644 index 0000000..88c7b3c --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/layout.json @@ -0,0 +1,5 @@ +{ + "layout.nav.apiAccess": "Доступ к API", + "layout.footer.terms": "Условия", + "layout.footer.privacy": "Конфиденциальность" +} diff --git a/frontend/src/lib/i18n/messages/ru/login.json b/frontend/src/lib/i18n/messages/ru/login.json new file mode 100644 index 0000000..ea4fd84 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/login.json @@ -0,0 +1,18 @@ +{ + "login.errorTitle": "Login Error", + "login.welcomeBack": "Welcome back", + "login.signInToContinue": "Sign in to continue translating", + "login.email": "Email", + "login.emailPlaceholder": "you@example.com", + "login.password": "Password", + "login.forgotPassword": "Forgot password?", + "login.passwordPlaceholder": "••••••••", + "login.signingIn": "Signing in...", + "login.signIn": "Sign In", + "login.noAccount": "Don't have an account?", + "login.signUpFree": "Sign up for free", + "login.orContinueWith": "или продолжить по электронной почте", + "login.google.connecting": "Подключение…", + "login.google.errorGeneric": "Произошла ошибка при входе через Google.", + "login.google.errorFailed": "Не удалось войти через Google. Повторите попытку." +} diff --git a/frontend/src/lib/i18n/messages/ru/memento.json b/frontend/src/lib/i18n/messages/ru/memento.json new file mode 100644 index 0000000..58a5668 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/memento.json @@ -0,0 +1,6 @@ +{ + "memento.title": "Откройте Momento", + "memento.slogan": "Momento — это больше, чем приложение для заметок. Это интеллектуальная экосистема, которая связывает, анализирует и развивает ваши идеи в реальном времени с помощью 6 ИИ-агентов и продвинутого семантического поиска.", + "memento.ctaFree": "Начать бесплатно", + "memento.ctaMore": "Узнать больше" +} diff --git a/frontend/src/lib/i18n/messages/ru/pricing.json b/frontend/src/lib/i18n/messages/ru/pricing.json new file mode 100644 index 0000000..8c867ff --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/pricing.json @@ -0,0 +1,151 @@ +{ + "pricing.nav.back": "Назад", + "pricing.nav.home": "Главная", + "pricing.nav.mySubscription": "Моя подписка", + "pricing.header.badge": "ИИ-модели обновлены — март 2026", + "pricing.header.title": "Тариф для любых задач", + "pricing.header.subtitle": "Переводите документы Word, Excel и PowerPoint с сохранением исходного форматирования. Без API-ключей.", + "pricing.billing.monthly": "Ежемесячно", + "pricing.billing.yearly": "Ежегодно", + "pricing.plans.free.name": "Бесплатный", + "pricing.plans.starter.name": "Starter", + "pricing.plans.pro.name": "Pro", + "pricing.plans.business.name": "Business", + "pricing.plans.enterprise.name": "Enterprise", + "pricing.plans.free.description": "Отлично для знакомства с приложением", + "pricing.plans.starter.description": "Для частных лиц и небольших проектов", + "pricing.plans.pro.description": "Для профессионалов и растущих команд", + "pricing.plans.business.description": "Для команд и организаций", + "pricing.plans.enterprise.description": "Индивидуальные решения для крупных организаций", + "pricing.plans.pro.highlight": "Самый популярный", + "pricing.plans.pro.badge": "ПОПУЛЯРНЫЙ", + "pricing.plans.enterprise.badge": "ПО ЗАПРОСУ", + "pricing.plans.free.feat1": "5 документов / месяц", + "pricing.plans.free.feat2": "До 15 страниц на документ", + "pricing.plans.free.feat3": "Google Переводчик включён", + "pricing.plans.free.feat4": "Все языки (130+)", + "pricing.plans.free.feat5": "Поддержка сообщества", + "pricing.plans.starter.feat1": "50 документов / месяц", + "pricing.plans.starter.feat2": "До 50 страниц на документ", + "pricing.plans.starter.feat3": "Google Переводчик + DeepL", + "pricing.plans.starter.feat4": "Файлы до 10 МБ", + "pricing.plans.starter.feat5": "Поддержка по эл. почте", + "pricing.plans.starter.feat6": "История за 30 дней", + "pricing.plans.pro.feat1": "200 документов / месяц", + "pricing.plans.pro.feat2": "До 200 страниц на документ", + "pricing.plans.pro.feat3": "Базовый ИИ-перевод", + "pricing.plans.pro.feat4": "Google Переводчик + DeepL", + "pricing.plans.pro.feat5": "Файлы до 25 МБ", + "pricing.plans.pro.feat6": "Пользовательские глоссарии", + "pricing.plans.pro.feat7": "Приоритетная поддержка", + "pricing.plans.pro.feat8": "История за 90 дней", + "pricing.plans.business.feat1": "1 000 документов / месяц", + "pricing.plans.business.feat2": "До 500 страниц на документ", + "pricing.plans.business.feat3": "Базовый + Премиум ИИ (Claude Haiku)", + "pricing.plans.business.feat4": "Все провайдеры перевода", + "pricing.plans.business.feat5": "Файлы до 50 МБ", + "pricing.plans.business.feat6": "Доступ к API (10 000 вызовов/мес.)", + "pricing.plans.business.feat7": "Вебхуки уведомлений", + "pricing.plans.business.feat8": "Выделенная поддержка", + "pricing.plans.business.feat9": "История за 1 год", + "pricing.plans.business.feat10": "Расширенная аналитика", + "pricing.plans.enterprise.feat1": "Безлимитные документы", + "pricing.plans.enterprise.feat2": "Все ИИ-модели (GPT-5, Claude Opus 4.6…)", + "pricing.plans.enterprise.feat3": "Локальное развёртывание или выделенное облако", + "pricing.plans.enterprise.feat4": "SLA 99,9 % гарантировано", + "pricing.plans.enterprise.feat5": "Выделенная поддержка 24/7", + "pricing.plans.enterprise.feat6": "White-label", + "pricing.plans.enterprise.feat7": "Безлимитные команды", + "pricing.plans.enterprise.feat8": "Индивидуальные интеграции", + "pricing.card.onRequest": "По запросу", + "pricing.card.free": "Бесплатно", + "pricing.card.perMonth": "/мес.", + "pricing.card.billedYearly": "К оплате {price} € / год", + "pricing.card.documents": "Документы", + "pricing.card.pagesMax": "Макс. страниц", + "pricing.card.aiTranslation": "ИИ-перевод", + "pricing.card.unlimited": "Безлимит", + "pricing.card.perMonthStat": "/ месяц", + "pricing.card.perDoc": "стр. / док.", + "pricing.card.aiEssential": "Базовый", + "pricing.card.aiEssentialPremium": "Базовый + Премиум", + "pricing.card.aiCustom": "Индивидуальный", + "pricing.card.myPlan": "Мой тариф", + "pricing.card.managePlan": "Управлять тарифом", + "pricing.card.startFree": "Начать бесплатно", + "pricing.card.contactUs": "Связаться с нами", + "pricing.card.choosePlan": "Выбрать этот тариф", + "pricing.card.processing": "Обработка…", + "pricing.comparison.title": "Подробное сравнение", + "pricing.comparison.subtitle": "Всё, что входит в каждый тариф", + "pricing.comparison.feature": "Функция", + "pricing.comparison.docsPerMonth": "Документы / месяц", + "pricing.comparison.pagesMaxPerDoc": "Макс. страниц / документ", + "pricing.comparison.maxFileSize": "Макс. размер файла", + "pricing.comparison.googleTranslation": "Google Переводчик", + "pricing.comparison.deepl": "DeepL", + "pricing.comparison.aiEssential": "Базовый ИИ-перевод", + "pricing.comparison.aiPremium": "Премиум ИИ-перевод", + "pricing.comparison.apiAccess": "Доступ к API", + "pricing.comparison.priorityProcessing": "Приоритетная обработка", + "pricing.comparison.support": "Поддержка", + "pricing.comparison.support.community": "Сообщество", + "pricing.comparison.support.email": "Эл. почта", + "pricing.comparison.support.priority": "Приоритетная", + "pricing.comparison.support.dedicated": "Выделенная", + "pricing.comparison.mb": "МБ", + "pricing.credits.title": "Дополнительные кредиты", + "pricing.credits.subtitle": "Нужно больше? Купите кредиты поштучно, без подписки.", + "pricing.credits.perPage": "1 кредит = 1 переведённая страница.", + "pricing.credits.bestValue": "Лучшая ценность", + "pricing.credits.unit": "кредитов", + "pricing.credits.centsPerCredit": "коп. / кредит", + "pricing.credits.buy": "Купить", + "pricing.trust.encryption.title": "Сквозное шифрование", + "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 при хранении", + "pricing.trust.languages.title": "130+ языков", + "pricing.trust.languages.sub": "Включая арабский, персидский, иврит (RTL)", + "pricing.trust.parallel.title": "Параллельная обработка", + "pricing.trust.parallel.sub": "Сверхбыстрая многопоточная ИИ", + "pricing.trust.availability.title": "Доступно 24/7", + "pricing.trust.availability.sub": "99,9 % гарантированный аптайм", + "pricing.aiModels.title": "Наши ИИ-модели — март 2026", + "pricing.aiModels.essential.title": "Базовый ИИ-перевод", + "pricing.aiModels.essential.plan": "Тариф Pro", + "pricing.aiModels.essential.descPrefix": "На базе", + "pricing.aiModels.essential.descSuffix": "— самой экономичной ИИ-модели 2026 года. Качество на уровне frontier-моделей при стоимости в десятки раз ниже.", + "pricing.aiModels.essential.modelName": "наша базовая ИИ-модель", + "pricing.aiModels.essential.context": "163K токенов контекста", + "pricing.aiModels.essential.value": "Отличное соотношение цены и качества", + "pricing.aiModels.premium.title": "Премиум ИИ-перевод", + "pricing.aiModels.premium.plan": "Тариф Business", + "pricing.aiModels.premium.descPrefix": "На базе", + "pricing.aiModels.premium.descSuffix": "от Anthropic — высокая точность на юридических, медицинских и сложных технических документах.", + "pricing.aiModels.premium.context": "200K токенов контекста", + "pricing.aiModels.premium.precision": "Наивысшая точность", + "pricing.faq.title": "Часто задаваемые вопросы", + "pricing.faq.q1": "Могу ли я сменить тариф в любое время?", + "pricing.faq.a1": "Да. Повышение тарифа применяется сразу с пересчётом. Понижение вступает в силу в конце текущего периода.", + "pricing.faq.q2": "Что такое «Базовый ИИ-перевод»?", + "pricing.faq.a2": "Это наш ИИ-движок. Он понимает контекст ваших документов, сохраняет вёрстку и обрабатывает технические термины намного лучше классического перевода.", + "pricing.faq.q3": "В чём разница между базовым и премиум ИИ-переводом?", + "pricing.faq.a3": "Базовый ИИ использует оптимизированную модель (отличное соотношение цены и качества). Премиум ИИ использует Claude 3.5 Haiku от Anthropic, более точный на юридических, медицинских и сложных технических документах.", + "pricing.faq.q4": "Сохраняются ли мои документы после перевода?", + "pricing.faq.a4": "Переведённые файлы доступны в зависимости от тарифа (30 дней Starter, 90 дней Pro, 1 год Business). Они зашифрованы при хранении и передаче.", + "pricing.faq.q5": "Что произойдёт при превышении месячной квоты?", + "pricing.faq.a5": "Вы можете докупить кредиты поштучно или повысить тариф. Уведомление приходит при достижении 80 % использования.", + "pricing.faq.q6": "Есть ли бесплатный пробный период для платных тарифов?", + "pricing.faq.a6": "Бесплатный тариф постоянный и не требует банковской карты. Для тарифов Pro и Business свяжитесь с нами для получения 14-дневного пробного доступа.", + "pricing.faq.q7": "Какие форматы файлов поддерживаются?", + "pricing.faq.a7": "Word (.docx), Excel (.xlsx/.xls), PowerPoint (.pptx), а скоро и PDF. Все тарифы поддерживают одинаковые форматы.", + "pricing.cta.title": "Готовы начать?", + "pricing.cta.subtitle": "Начните бесплатно, без банковской карты. Повысьте тариф, когда понадобится.", + "pricing.cta.createAccount": "Создать бесплатный аккаунт", + "pricing.cta.login": "Войти", + "pricing.toast.demo": "Деморежим — Stripe ещё не настроен. В рабочей среде вы были бы перенаправлены на страницу оплаты для активации тарифа {planId}.", + "pricing.toast.networkError": "Сетевая ошибка. Пожалуйста, попробуйте снова.", + "pricing.toast.paymentError": "Ошибка при создании платежа.", + "pricing.dashboard": "Панель", + "pricing.okSymbol": "✓", + "pricing.errSymbol": "✕" +} diff --git a/frontend/src/lib/i18n/messages/ru/profile.json b/frontend/src/lib/i18n/messages/ru/profile.json new file mode 100644 index 0000000..2b18634 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/profile.json @@ -0,0 +1,58 @@ +{ + "profile.header.title": "Мой профиль", + "profile.header.subtitle": "Управление аккаунтом и настройками.", + "profile.tabs.account": "Аккаунт", + "profile.tabs.subscription": "Подписка", + "profile.tabs.preferences": "Настройки", + "profile.account.user": "Пользователь", + "profile.account.memberSince": "Участник с", + "profile.plan.label": "Тариф", + "profile.plan.free": "Free", + "profile.plan.starter": "Starter", + "profile.plan.pro": "Pro", + "profile.plan.business": "Business", + "profile.plan.enterprise": "Enterprise", + "profile.plan.pricePerMonth": "{price} €/мес.", + "profile.subscription.canceling": "Отменяется", + "profile.subscription.active": "Активна", + "profile.subscription.unknown": "Неизвестно", + "profile.subscription.accessUntil": "Доступ до", + "profile.subscription.renewalOn": "Продление", + "profile.subscription.upgradePlan": "Перейти на платный тариф", + "profile.subscription.changePlan": "Сменить тариф", + "profile.subscription.manageBilling": "Управление оплатой", + "profile.subscription.billingUnavailable": "Портал оплаты недоступен.", + "profile.subscription.billingError": "Ошибка доступа к порталу оплаты.", + "profile.subscription.cancelSuccess": "Подписка отменена. Доступ сохраняется до конца текущего периода.", + "profile.subscription.cancelError": "Ошибка при отмене.", + "profile.subscription.networkError": "Ошибка сети.", + "profile.usage.title": "Использование за этот месяц", + "profile.usage.resetOn": "Сброс", + "profile.usage.documents": "Документы", + "profile.usage.pages": "Страницы", + "profile.usage.extraCredits": "дополнительный кредит", + "profile.usage.extraCreditsPlural": "дополнительных кредитов", + "profile.usage.quotaReached": "Лимит достигнут", + "profile.usage.quotaReachedDesc": "Перейдите на более высокий тариф, чтобы продолжить.", + "profile.usage.unlockMore": "Разблокируйте больше переводов с платным тарифом.", + "profile.usage.viewPlans": "Посмотреть тарифы", + "profile.usage.includedInPlan": "Включено в ваш тариф", + "profile.danger.title": "Опасная зона", + "profile.danger.description": "Отмена вступает в силу в конце текущего периода. Доступ сохраняется до этой даты.", + "profile.danger.confirm": "Вы уверены? Это действие нельзя отменить.", + "profile.danger.confirmCancel": "Подтвердить отмену", + "profile.danger.cancelSubscription": "Отменить мою подписку", + "profile.danger.keep": "Нет, оставить", + "profile.prefs.interfaceLang": "Язык интерфейса", + "profile.prefs.interfaceLangDesc": "Язык определяется автоматически на основе настроек браузера. Вы можете изменить его вручную.", + "profile.prefs.defaultTargetLang": "Язык перевода по умолчанию", + "profile.prefs.selectLanguage": "Выберите язык", + "profile.prefs.defaultTargetLangDesc": "Этот язык будет автоматически выбираться для ваших переводов.", + "profile.prefs.save": "Сохранить", + "profile.prefs.theme": "Тема", + "profile.prefs.themeDesc": "Выберите внешний вид интерфейса", + "profile.prefs.cache": "Кэш", + "profile.prefs.cacheDesc": "Очистка локального кэша может решить некоторые проблемы отображения.", + "profile.prefs.clearing": "Очистка...", + "profile.prefs.clearCache": "Очистить кэш" +} diff --git a/frontend/src/lib/i18n/messages/ru/providerSelector.json b/frontend/src/lib/i18n/messages/ru/providerSelector.json new file mode 100644 index 0000000..89c8c4a --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/providerSelector.json @@ -0,0 +1,7 @@ +{ + "providerSelector.noClassic": "Стандартный переводчик недоступен.", + "providerSelector.noLlm": "Модель ИИ не настроена.", + "providerSelector.costOne": "Стоимость: 1 кредит за страницу", + "providerSelector.costFive": "Стоимость: 5 кредитов за страницу (Премиум-фактор)", + "providerSelector.unlockContextual": "Разблокируйте премиум-контекстный перевод для ваших документов." +} diff --git a/frontend/src/lib/i18n/messages/ru/providerTheme.json b/frontend/src/lib/i18n/messages/ru/providerTheme.json new file mode 100644 index 0000000..e864f63 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/providerTheme.json @@ -0,0 +1,29 @@ +{ + "providerTheme.deepseek.badge": "Базовый", + "providerTheme.deepseek.subBadge": "Технический и экономичный", + "providerTheme.deepseek.desc": "Ультраточная и экономичная трансляция, идеально для технических документов и кода.", + "providerTheme.openai.badge": "Премиум", + "providerTheme.openai.subBadge": "Высокая точность", + "providerTheme.openai.desc": "Мировой стандарт ИИ. Максимальная согласованность и строгое соблюдение стиля.", + "providerTheme.minimax.badge": "Продвинутый", + "providerTheme.minimax.subBadge": "Производительность", + "providerTheme.minimax.desc": "Невероятная скорость и превосходное понимание сложных структур.", + "providerTheme.openrouter.badge": "Экспресс", + "providerTheme.openrouter.subBadge": "Мульти-модель", + "providerTheme.openrouter.desc": "Единый доступ к лучшим open-source моделям, оптимизированным для перевода.", + "providerTheme.openrouter_premium.badge": "Ультра", + "providerTheme.openrouter_premium.subBadge": "Максимальный контекст", + "providerTheme.openrouter_premium.desc": "С помощью современных моделей (GPT-4o, Claude Sonnet 4.6) для длинных документов.", + "providerTheme.zai.badge": "Специализированный", + "providerTheme.zai.subBadge": "Финансы и право", + "providerTheme.zai.desc": "Модель точно настроена для требовательных бизнес-терминологий (юриспруденция, финансы).", + "providerTheme.default.badge": "Современный", + "providerTheme.default.subBadge": "ИИ-рассуждение", + "providerTheme.default.desc": "Перевод большой языковой моделью (LLM) с расширенным семантическим анализом.", + "providerTheme.classic.google.label": "Google Переводчик", + "providerTheme.classic.google.desc": "Сверхбыстрый перевод более 130 языков. Рекомендуется для общих потоков.", + "providerTheme.classic.deepl.label": "DeepL Pro", + "providerTheme.classic.deepl.desc": "Высокоточная трансляция, известная своей беглостью и естественностью формулировок.", + "providerTheme.classic.google_cloud.label": "Google Cloud API", + "providerTheme.classic.google_cloud.desc": "Профессиональный облачный движок, оптимизированный для обработки больших объёмов документов." +} diff --git a/frontend/src/lib/i18n/messages/ru/register.json b/frontend/src/lib/i18n/messages/ru/register.json new file mode 100644 index 0000000..152bc6c --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/register.json @@ -0,0 +1,29 @@ +{ + "register.title": "Создать аккаунт", + "register.subtitle": "Начните переводить бесплатно", + "register.error.failed": "Ошибка регистрации", + "register.name.label": "Имя", + "register.name.placeholder": "Ваше имя", + "register.name.error": "Имя должно содержать не менее 2 символов", + "register.email.label": "Электронная почта", + "register.email.placeholder": "you@example.com", + "register.email.error": "Недействительный адрес эл. почты", + "register.password.label": "Пароль", + "register.password.error": "Пароль должен содержать не менее 8 символов, включая заглавную букву, строчную букву и цифру", + "register.password.show": "Показать пароль", + "register.password.hide": "Скрыть пароль", + "register.password.strengthLabel": "Надёжность:", + "register.password.strength.weak": "Слабая", + "register.password.strength.medium": "Средняя", + "register.password.strength.strong": "Сильная", + "register.confirmPassword.label": "Подтвердите пароль", + "register.confirmPassword.error": "Пароли не совпадают", + "register.confirmPassword.show": "Показать", + "register.confirmPassword.hide": "Скрыть", + "register.submit.creating": "Создание аккаунта...", + "register.submit.create": "Создать аккаунт", + "register.hasAccount": "Уже есть аккаунт?", + "register.login": "Войти", + "register.terms.prefix": "Создавая аккаунт, вы принимаете наши", + "register.terms.link": "условия использования" +} diff --git a/frontend/src/lib/i18n/messages/ru/resetPassword.json b/frontend/src/lib/i18n/messages/ru/resetPassword.json new file mode 100644 index 0000000..680714f --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/resetPassword.json @@ -0,0 +1,22 @@ +{ + "resetPassword.passwordRequirements": "Password must contain at least 8 characters, one uppercase, one lowercase, and one number", + "resetPassword.passwordMismatch": "Passwords do not match", + "resetPassword.tokenMissing": "Missing token. Please use the link received by email.", + "resetPassword.error": "An error occurred", + "resetPassword.invalidLink": "Invalid link", + "resetPassword.invalidLinkMessage": "This reset link is invalid. Please request a new one.", + "resetPassword.requestNewLink": "Request new link", + "resetPassword.successTitle": "Password reset", + "resetPassword.newPasswordTitle": "New password", + "resetPassword.successSubtitle": "You will be redirected to login", + "resetPassword.subtitle": "Set your new password", + "resetPassword.successMessage": "Your password has been successfully reset. You will be redirected to the login page.", + "resetPassword.newPassword": "New password", + "resetPassword.showPassword": "Show password", + "resetPassword.hidePassword": "Hide password", + "resetPassword.confirmPassword": "Confirm password", + "resetPassword.resetting": "Resetting...", + "resetPassword.resetPassword": "Reset password", + "resetPassword.backToLogin": "Back to login", + "resetPassword.loading": "Loading..." +} diff --git a/frontend/src/lib/i18n/messages/ru/services.json b/frontend/src/lib/i18n/messages/ru/services.json new file mode 100644 index 0000000..cb8b792 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/services.json @@ -0,0 +1,14 @@ +{ + "services.title": "Провайдеры перевода", + "services.subtitle": "Провайдеры настраиваются администратором. Вы можете увидеть, какие из них доступны для вашего аккаунта.", + "services.loading": "Загрузка провайдеров...", + "services.noProviders": "Провайдеры не настроены. Обратитесь к администратору.", + "services.classic": "Классический перевод", + "services.llmPro": "LLM · Контекстный (Pro)", + "services.available": "Доступен", + "services.model": "Модель", + "services.adminOnly.title": "Настройка провайдеров доступна только администратору", + "services.adminOnly.desc": "API-ключи, выбор моделей и активация провайдеров управляются исключительно администратором в панели управления. Вам не нужно вводить API-ключ.", + "services.fallback.google.label": "Google Переводчик", + "services.fallback.google.desc": "Быстрый перевод, 130+ языков" +} diff --git a/frontend/src/lib/i18n/messages/ru/settings.json b/frontend/src/lib/i18n/messages/ru/settings.json new file mode 100644 index 0000000..58d75d6 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/settings.json @@ -0,0 +1,20 @@ +{ + "settings.title": "Настройки", + "settings.subtitle": "Общая конфигурация приложения", + "settings.formats.title": "Поддерживаемые форматы", + "settings.formats.subtitle": "Типы документов, которые можно перевести", + "settings.formats.formulas": "Формулы", + "settings.formats.styles": "Стили", + "settings.formats.images": "Изображения", + "settings.formats.headers": "Колонтитулы", + "settings.formats.tables": "Таблицы", + "settings.formats.slides": "Слайды", + "settings.formats.notes": "Заметки", + "settings.cache.title": "Кэш", + "settings.cache.desc": "Очистка локального кэша может решить некоторые проблемы отображения.", + "settings.cache.clearing": "Очистка...", + "settings.cache.clear": "Очистить кэш", + "settings.formats.excel.name": "Excel", + "settings.formats.word.name": "Word", + "settings.formats.powerpoint.name": "PowerPoint" +} diff --git a/frontend/src/lib/i18n/messages/ru/translate.json b/frontend/src/lib/i18n/messages/ru/translate.json new file mode 100644 index 0000000..6b09929 --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/translate.json @@ -0,0 +1,92 @@ +{ + "translate.mode.label": "Mode de traduction", + "translate.mode.classic": "Classique", + "translate.mode.classicDesc": "Rapide", + "translate.mode.proLlm": "Pro LLM", + "translate.mode.proLlmDesc": "Contextuel", + "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", + "translate.mode.upgradeLink": "Passer à Pro", + "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", + "translate.glossary.title": "Глоссарий", + "translate.glossary.select": "Выбрать глоссарий", + "translate.glossary.none": "Нет", + "translate.glossary.terms": "терминов", + "translate.glossary.proOnly": "Обновитесь до Pro для использования глоссариев", + "translate.glossary.myGlossaries": "Мои глоссарии", + "translate.glossary.fromTemplate": "Создать из шаблона", + "translate.glossary.noGlossaryForPair": "Нет глоссария для", + "translate.glossary.noGlossaries": "Нет глоссариев", + "translate.glossary.loading": "Загрузка...", + "translate.glossary.classicMode": "Нейтральный движок без глоссария (только ИИ)", + "translate.glossary.selectPlaceholder": "Выбрать глоссарий...", + "translate.glossary.multilingual": "МУЛЬТИЯЗЫЧНЫЙ", + "translate.glossary.noGlossaryAvailable": "Нет доступных глоссариев", + "translate.glossary.filterByLang": "Фильтр по языку", + "translate.glossary.active": "Активно", + "translate.glossary.inactive": "Неактивно", + "translate.glossary.availableTemplates": "Доступные шаблоны", + "translate.glossary.importing": "Импорт...", + "translate.glossary.imported": "(Импортировано)", + "translate.glossary.noGlossaryForSource": "Нет глоссария или шаблона для исходного языка", + "translate.glossary.createGlossary": "Создать глоссарий", + "translate.glossary.showAll": "Показать все глоссарии", + "translate.glossary.activePreview": "Предпросмотр активных совпадений:", + "translate.glossary.total": "всего", + "translate.glossary.moreTerms": "других терминов", + "translate.glossary.noTerms": "Нет терминов в этом глоссарии.", + "translate.glossary.sourceTerm": "Исходный термин", + "translate.glossary.translation": "Перевод", + "translate.glossary.addTerm": "Добавить термин", + "translate.glossary.disabledMode": "Нейтральный движок без применённого глоссария", + "translate.glossary.addTermError": "Ошибка при добавлении термина", + "translate.glossary.networkError": "Сетевая ошибка", + "translate.glossary.importFailed": "Ошибка импорта ({status})", + "translate.glossary.helpText": "Глоссарий обеспечивает точный перевод терминов. Выберите глоссарий, исходный язык которого соответствует оригинальному языку вашего документа.", + "translate.glossary.sourceWarning": "Внимание: Этот глоссарий использует исходный язык", + "translate.glossary.sourceWarningBut": "но ваш документ настроен на", + "translate.glossary.targetWarning": "Несовместимость цели: Этот глоссарий предназначен для перевода на", + "translate.glossary.targetWarningBut": "но ваш документ нацелен на", + "translate.glossary.targetWarningEnd": "Термины могут быть нерелевантны.", + "translate.header.processing": "Идёт обработка", + "translate.header.aiActive": "ИИ-анализ активен", + "translate.header.aiActiveDesc": "Ваша компоновка сохраняется нашим контекстным движком.", + "translate.header.completed": "Завершено", + "translate.header.completedTitle": "Перевод завершён", + "translate.header.proSpace": "Pro-пространство", + "translate.header.translateDoc": "Перевести документ", + "translate.header.translateDocDesc": "Сохраните оригинальную компоновку с нашим движком перевода сверхвысокой точности.", + "translate.upload.nativeFormat": "Родной формат", + "translate.fileType.word": "Word (.docx)", + "translate.fileType.excel": "Excel (.xlsx)", + "translate.fileType.slides": "Слайды (.pptx)", + "translate.fileType.pdf": "PDF (.pdf)", + "translate.startTranslation": "Начать перевод", + "translate.submit": "Отправка…", + "translate.chooseTargetLang": "Пожалуйста, выберите целевой язык", + "translate.pleaseLoadFile": "Пожалуйста, сначала загрузите файл", + "translate.contextEngineActive": "Контекстный движок активен", + "translate.phase1": "Фаза 1: Инициализация", + "translate.phase2": "Фаза 2: Контекстная реконструкция", + "translate.stat.segments": "сегментов", + "translate.stat.precision": "точность", + "translate.stat.speedLabel": "скорость", + "translate.stat.turbo": "Турбо", + "translate.stat.time": "время", + "translate.complete.masterQuality": "✓ Мастер-качество", + "translate.download": "Скачать", + "translate.newTranslation": "+ Новый перевод", + "translate.failedTitle": "Ошибка перевода", + "translate.retry": "Повторить", + "translate.uploadAnother": "Загрузить другой файл", + "translate.monitor": "ИИ-монитор", + "translate.summary": "Сводка", + "translate.cancelProcess": "⟳ Отменить процесс", + "translate.layoutIntegrity": "Целостность макета", + "translate.secureHundred": "100% БЕЗОПАСНО", + "translate.okHundred": "100% OK", + "translate.preserveLayout": "Сохранить макет", + "translate.preserveLayoutDesc": "Сохранить макет", + "translate.textOnly": "Только текст", + "translate.textOnlyDesc": "Быстрый перевод только текста", + "translate.unavailableStandard": "Недоступно в стандартном режиме (только ИИ)" +} diff --git a/frontend/src/lib/i18n/messages/ru/translateComplete.json b/frontend/src/lib/i18n/messages/ru/translateComplete.json new file mode 100644 index 0000000..e2c465c --- /dev/null +++ b/frontend/src/lib/i18n/messages/ru/translateComplete.json @@ -0,0 +1,6 @@ +{ + "translateComplete.highQuality": "Высокое качество", + "translateComplete.segments": "Сегменты", + "translateComplete.characters": "Символы", + "translateComplete.confidence": "Уверенность" +} diff --git a/frontend/src/lib/i18n/messages/zh/admin.json b/frontend/src/lib/i18n/messages/zh/admin.json new file mode 100644 index 0000000..ffcb049 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/admin.json @@ -0,0 +1,48 @@ +{ + "admin.login.title": "管理后台", + "admin.login.required": "需要登录", + "admin.login.password": "管理员密码", + "admin.login.connecting": "连接中...", + "admin.login.access": "进入管理面板", + "admin.login.restricted": "仅限管理员", + "admin.layout.checking": "正在验证身份...", + "admin.dashboard.title": "管理仪表盘", + "admin.dashboard.subtitle": "管理员控制面板", + "admin.dashboard.refresh": "刷新", + "admin.dashboard.refreshTooltip": "刷新仪表盘数据", + "admin.dashboard.config": "系统配置", + "admin.dashboard.maxFileSize": "最大文件大小:", + "admin.dashboard.translationService": "翻译服务:", + "admin.dashboard.formats": "支持格式:", + "admin.nav.dashboard": "Dashboard", + "admin.nav.users": "用户", + "admin.nav.pricing": "定价 & Stripe", + "admin.nav.providers": "服务商", + "admin.nav.system": "系统", + "admin.nav.logs": "日志", + "admin.users.title": "用户管理", + "admin.users.subtitle": "查看和管理用户账户", + "admin.users.planUpdated": "套餐已更新", + "admin.users.planChanged": "套餐已成功更改为\\\"{plan}\\\"。", + "admin.users.unknownError": "未知错误", + "admin.users.error": "错误", + "admin.users.planUpdateError": "无法更新套餐:{message}", + "admin.users.noKeys": "无密钥", + "admin.users.noKeysDesc": "该用户没有有效的API密钥。", + "admin.users.keysRevoked": "密钥已撤销", + "admin.users.keysRevokedDesc": "{count}个API密钥已成功撤销。", + "admin.users.revokeError": "无法撤销密钥:{message}", + "admin.users.retry": "重试", + "admin.system.title": "系统", + "admin.system.subtitle": "监控系统状态并管理资源", + "admin.system.quotas": "翻译配额", + "admin.system.resetQuotas": "重置月度配额", + "admin.system.resetting": "重置中...", + "admin.system.reset": "重置", + "admin.system.allOperational": "所有系统正常运行", + "admin.system.issuesDetected": "检测到系统问题", + "admin.system.waitingData": "等待数据...", + "admin.system.purging": "清理中...", + "admin.system.clean": "清理", + "admin.system.purge": "清除" +} diff --git a/frontend/src/lib/i18n/messages/zh/apiKeys.json b/frontend/src/lib/i18n/messages/zh/apiKeys.json new file mode 100644 index 0000000..b8319f8 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/apiKeys.json @@ -0,0 +1,72 @@ +{ + "apiKeys.webhook.title": "Intégration Webhook", + "apiKeys.webhook.descriptionBefore": "Passez un paramètre ", + "apiKeys.webhook.descriptionAfter": " pour recevoir une requête POST lorsque votre traduction est terminée.", + "apiKeys.webhook.codeParam": "webhook_url", + "apiKeys.title": "API 密钥", + "apiKeys.subtitle": "管理用于编程访问翻译 API 的 API 密钥。", + "apiKeys.loading": "加载中...", + "apiKeys.sectionTitle": "API 与自动化", + "apiKeys.sectionDesc": "生成和管理用于自动化工作流的 API 密钥", + "apiKeys.keysUsed": "已使用 {total} / {max} 个密钥", + "apiKeys.maxReached": "已达到密钥上限。请吊销现有密钥后再生成新密钥。", + "apiKeys.canGenerate": "还可以生成 {count} 个密钥", + "apiKeys.canGeneratePlural": "还可以生成 {count} 个密钥", + "apiKeys.generateNew": "生成新密钥", + "apiKeys.keyRevoked": "密钥已吊销", + "apiKeys.keyRevokedDesc": "API 密钥已成功吊销。", + "apiKeys.keyNotFound": "密钥未找到", + "apiKeys.keyNotFoundDesc": "API 密钥已不存在。可能已被吊销。", + "apiKeys.error": "错误", + "apiKeys.revokeError": "吊销 API 密钥失败。请重试。", + "apiKeys.limitReached": "已达上限", + "apiKeys.limitReachedDesc": "您已达到最多 10 个 API 密钥的限制。请吊销现有密钥后再生成新密钥。", + "apiKeys.proRequired": "需要 Pro 功能", + "apiKeys.proRequiredDesc": "API 密钥是 Pro 功能。请升级您的账户。", + "apiKeys.generateError": "生成 API 密钥失败。请重试。", + "apiKeys.upgrade.title": "API 密钥", + "apiKeys.upgrade.subtitle": "通过 API 访问自动化翻译", + "apiKeys.upgrade.feat1": "生成无限 API 密钥", + "apiKeys.upgrade.feat2": "自动化文档翻译", + "apiKeys.upgrade.feat3": "Webhook 通知", + "apiKeys.upgrade.feat4": "LLM 翻译模式", + "apiKeys.upgrade.proFeature": "API 密钥是{pro}功能。升级以解锁 API 自动化。", + "apiKeys.upgrade.pro": "Pro", + "apiKeys.upgrade.cta": "升级到 Pro", + "apiKeys.dialog.maxTitle": "已达最大密钥数", + "apiKeys.dialog.maxDesc": "您已达到最多 10 个 API 密钥的限制。请在生成新密钥前吊销现有密钥。", + "apiKeys.dialog.close": "关闭", + "apiKeys.dialog.generated": "API 密钥已生成!", + "apiKeys.dialog.generatedDesc": "新的 API 密钥已创建。请立即复制 - 之后将不再显示。", + "apiKeys.dialog.important": "重要提示:", + "apiKeys.dialog.importantDesc": "这是您唯一一次看到此密钥。请妥善保存。", + "apiKeys.dialog.apiKey": "API 密钥", + "apiKeys.dialog.name": "名称:", + "apiKeys.dialog.done": "完成", + "apiKeys.dialog.copied": "我已复制密钥", + "apiKeys.dialog.generateTitle": "生成新 API 密钥", + "apiKeys.dialog.generateDesc": "创建用于编程访问翻译 API 的新 API 密钥。", + "apiKeys.dialog.keyName": "密钥名称(可选)", + "apiKeys.dialog.keyNamePlaceholder": "例如:生产环境、测试环境", + "apiKeys.dialog.keyNameHint": "一个描述性的名称,方便您以后识别此密钥。", + "apiKeys.dialog.nameTooLong": "名称不得超过 {max} 个字符", + "apiKeys.dialog.nameInvalid": "名称只能包含字母、数字、空格、连字符和下划线", + "apiKeys.dialog.cancel": "取消", + "apiKeys.dialog.generating": "生成中...", + "apiKeys.dialog.generate": "生成密钥", + "apiKeys.table.name": "名称", + "apiKeys.table.prefix": "前缀", + "apiKeys.table.created": "创建时间", + "apiKeys.table.lastUsed": "最后使用", + "apiKeys.table.never": "从未使用", + "apiKeys.table.actions": "操作", + "apiKeys.table.revoke": "吊销", + "apiKeys.table.copyPrefix": "复制密钥前缀", + "apiKeys.table.revokeKey": "吊销密钥", + "apiKeys.revokeDialog.title": "吊销 API 密钥", + "apiKeys.revokeDialog.desc": "确定要吊销密钥\\\"{name}\\\"吗?此操作不可撤销。", + "apiKeys.revokeDialog.confirm": "是,吊销", + "apiKeys.revokeDialog.cancel": "取消", + "apiKeys.noKeysGenerated": "未生成密钥", + "apiKeys.copied": "已复制!" +} diff --git a/frontend/src/lib/i18n/messages/zh/auth.json b/frontend/src/lib/i18n/messages/zh/auth.json new file mode 100644 index 0000000..b300370 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/auth.json @@ -0,0 +1,3 @@ +{ + "auth.brandName": "Wordly" +} diff --git a/frontend/src/lib/i18n/messages/zh/checkout.json b/frontend/src/lib/i18n/messages/zh/checkout.json new file mode 100644 index 0000000..0004927 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/checkout.json @@ -0,0 +1,12 @@ +{ + "checkout.activating": "正在激活…", + "checkout.activatingDesc": "我们正在更新您的订阅,请稍候。", + "checkout.paymentConfirmed": "支付已确认!", + "checkout.subscriptionActivated": "订阅已激活!", + "checkout.planActivated": "{plan} 套餐已激活!", + "checkout.redirectingToProfile": "正在跳转到您的个人资料…", + "checkout.paymentReceived": "已收到付款", + "checkout.redirecting": "正在跳转…", + "checkout.syncError": "同步错误", + "checkout.networkError": "网络错误。您的付款已确认 — 请重新加载您的个人资料。" +} diff --git a/frontend/src/lib/i18n/messages/zh/common.json b/frontend/src/lib/i18n/messages/zh/common.json new file mode 100644 index 0000000..ce300e5 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/common.json @@ -0,0 +1,4 @@ +{ + "common.loading": "加载中...", + "common.backToHome": "返回首页" +} diff --git a/frontend/src/lib/i18n/messages/zh/context.json b/frontend/src/lib/i18n/messages/zh/context.json new file mode 100644 index 0000000..c6b6fc1 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/context.json @@ -0,0 +1,25 @@ +{ + "context.proTitle": "Pro 功能", + "context.proDesc": "上下文和专业术语表适用于 Pro、Business 和 Enterprise 套餐。它们通过特定领域的指令和词汇提供更准确的翻译。", + "context.viewPlans": "查看套餐", + "context.title": "上下文与术语表", + "context.subtitle": "通过特定领域的指令和词汇提高翻译质量。", + "context.presets.title": "专业术语表", + "context.presets.desc": "加载包含指令和专业术语的完整术语表", + "context.instructions.title": "上下文指令", + "context.instructions.desc": "翻译过程中 AI 将遵循的指令", + "context.instructions.placeholder": "例如:您翻译 HVAC 技术文档。请使用精确的工程术语...", + "context.glossary.title": "技术术语表", + "context.glossary.desc": "格式:source=target(每行一个)。通过预设加载的术语表可编辑。", + "context.glossary.terms": "术语表中的术语数", + "context.clearAll": "全部清除", + "context.saving": "保存中...", + "context.save": "保存", + "context.presets.createGlossary": "创建术语表", + "context.presets.created": "术语表已创建", + "context.presets.createdDesc": "术语表 \\\"{name}\\\" 已创建,包含 {count} 个术语。", + "context.presets.hint": "点击预设以创建包含领域特定术语的术语表。在术语表部分管理您的术语表。", + "context.glossary.manage": "管理术语表", + "context.saved": "已保存", + "context.savedDesc": "您的上下文说明已保存。" +} diff --git a/frontend/src/lib/i18n/messages/zh/cookieConsent.json b/frontend/src/lib/i18n/messages/zh/cookieConsent.json new file mode 100644 index 0000000..ad195ae --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/cookieConsent.json @@ -0,0 +1,7 @@ +{ + "cookieConsent.title": "Wordly 的 Cookie", + "cookieConsent.description": "我们使用必要的 Cookie 以确保应用正常运行(会话、安全、语言)。在您的许可下,我们还会使用可选 Cookie 来衡量流量和改进产品。", + "cookieConsent.acceptAll": "全部接受", + "cookieConsent.essentialOnly": "仅限必要", + "cookieConsent.learnMore": "了解更多" +} diff --git a/frontend/src/lib/i18n/messages/zh/dashboard.json b/frontend/src/lib/i18n/messages/zh/dashboard.json new file mode 100644 index 0000000..2e128ff --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/dashboard.json @@ -0,0 +1,111 @@ +{ + "dashboard.nav.translate": "翻译", + "dashboard.nav.profile": "我的资料", + "dashboard.nav.settings": "设置", + "dashboard.nav.context": "上下文", + "dashboard.nav.services": "服务", + "dashboard.nav.apiKeys": "API 密钥", + "dashboard.nav.glossaries": "术语表", + "dashboard.header.title": "控制面板", + "dashboard.header.subtitle": "管理您的翻译", + "dashboard.header.toggleMenu": "菜单", + "dashboard.header.profileTitle": "我的资料", + "dashboard.sidebar.theme": "主题", + "dashboard.sidebar.signOut": "退出登录", + "dashboard.sidebar.backHome": "返回首页", + "dashboard.sidebar.upgradeToPro": "升级到 Pro →", + "dashboard.translate.pageTitle": "翻译文档", + "dashboard.translate.pageSubtitle": "导入文件并选择目标语言", + "dashboard.translate.errorNotificationTitle": "错误", + "dashboard.translate.dropzone.uploadAria": "文件拖放区", + "dashboard.translate.dropzone.title": "将文件拖放到此处", + "dashboard.translate.dropzone.subtitle": "或点击选择(DOCX、XLSX、PPTX、PDF)", + "dashboard.translate.dropzone.replaceFile": "替换文件", + "dashboard.translate.language.source": "源语言", + "dashboard.translate.language.target": "目标语言", + "dashboard.translate.language.loading": "正在加载语言…", + "dashboard.translate.language.autoDetect": "自动检测", + "dashboard.translate.language.selectPlaceholder": "选择…", + "dashboard.translate.language.loadErrorPrefix": "语言加载失败", + "dashboard.translate.provider.loading": "正在加载服务商…", + "dashboard.translate.provider.noneConfigured": "未配置服务商", + "dashboard.translate.provider.modelTitle": "模型", + "dashboard.translate.provider.sectionTitle": "服务商", + "dashboard.translate.provider.llmDivider": "AI · 上下文感知", + "dashboard.translate.provider.llmDividerPro": "AI · 上下文感知(专业版)", + "dashboard.translate.provider.upgrade": "升级到专业版", + "dashboard.translate.provider.upgradeSuffix": "以解锁 AI 翻译", + "dashboard.translate.trust.zeroRetention": "零数据留存", + "dashboard.translate.trust.deletedAfter": "处理完成后文件即被删除", + "dashboard.translate.actions.uploading": "正在上传…", + "dashboard.translate.actions.translate": "翻译", + "dashboard.translate.actions.filePrefix": "文件:", + "dashboard.translate.actions.cancel": "取消", + "dashboard.translate.actions.tryAgain": "重试", + "dashboard.translate.steps.uploading": "正在上传文件…", + "dashboard.translate.steps.starting": "正在开始翻译…", + "dashboard.translate.complete.title": "翻译完成!", + "dashboard.translate.complete.descNamed": "您的文件 {name} 已成功翻译。", + "dashboard.translate.complete.descGeneric": "您的文件已成功翻译。", + "dashboard.translate.complete.downloading": "正在下载…", + "dashboard.translate.complete.download": "下载", + "dashboard.translate.complete.newTranslation": "新建翻译", + "dashboard.translate.complete.toastOkTitle": "成功", + "dashboard.translate.complete.toastOkDesc": "{name} 已成功下载。", + "dashboard.translate.complete.toastFailTitle": "失败", + "dashboard.translate.complete.toastFailDesc": "翻译失败,请重试。", + "dashboard.translate.sourceDocument": "源文档", + "dashboard.translate.configuration": "配置", + "dashboard.translate.translating": "翻译进行中", + "dashboard.translate.liveMonitor": "实时监控", + "dashboard.translate.summary": "摘要", + "dashboard.translate.engine": "引擎", + "dashboard.translate.confidence": "置信度", + "dashboard.translate.cancel": "取消", + "dashboard.translate.segments": "片段", + "dashboard.translate.characters": "字符", + "dashboard.translate.elapsed": "已用时间", + "dashboard.translate.segPerMin": "片段/分钟", + "dashboard.translate.highQuality": "高质量", + "dashboard.translate.quality": "质量", + "dashboard.translate.completed": "翻译完成", + "dashboard.translate.replace": "替换", + "dashboard.translate.pdfMode.title": "PDF翻译模式", + "dashboard.translate.pdfMode.preserveLayout": "保留排版", + "dashboard.translate.pdfMode.textOnly": "仅文本", + "dashboard.translate.pdfMode.preserveLayoutDesc": "保留图片、表格和格式。适合简单PDF。", + "dashboard.translate.pdfMode.textOnlyDesc": "完美翻译所有文本。整洁输出,无排版问题。", + "dashboard.translate.pipeline.upload": "上传", + "dashboard.translate.pipeline.analyze": "分析", + "dashboard.translate.pipeline.translate": "翻译", + "dashboard.translate.pipeline.rebuild": "重建", + "dashboard.translate.pipeline.finalize": "完成", + "dashboard.translate.progress.processingFallback": "处理中…", + "dashboard.translate.progress.connectionLost": "连接已断开。正在重试…", + "dashboard.translate.progress.failedTitle": "翻译失败", + "dashboard.translate.error.unexpected": "发生了意外错误,请重试。", + "dashboard.translate.error.noResult": "翻译未产生结果。请确认文档包含文本,然后重试或选择其他引擎。", + "dashboard.translate.error.apiKey": "API 密钥无效或缺失。请联系管理员配置 API 密钥。", + "dashboard.translate.error.quota": "已达到使用限制。请稍后重试或选择其他引擎。", + "dashboard.translate.error.timeout": "翻译服务连接超时。请检查网络后重试。", + "dashboard.translate.error.sessionExpired": "会话已过期。点击重试以重新开始翻译。", + "dashboard.translate.error.empty": "文档似乎为空或不包含可翻译文本(扫描 PDF 图像?)。", + "dashboard.translate.error.unsupported": "不支持的文件格式或文件已损坏。", + "dashboard.translate.error.connection": "连接丢失。请检查网络后重试。", + "dashboard.translate.error.generic": "翻译失败:{detail}", + "dashboard.translate.error.title": "翻译失败", + "dashboard.translate.retry": "重试翻译", + "dashboard.translate.newFile": "新文件", + "dashboard.translate.modeAI": "AI 模式", + "dashboard.translate.modeClassic": "经典模式", + "dashboard.translate.glossaryLLMHint": "AI 模式下可使用术语表", + "dashboard.translate.submitting": "提交中...", + "dashboard.translate.submit": "开始翻译", + "dashboard.translate.noFile": "请先上传文件", + "dashboard.translate.noTargetLang": "请选择目标语言", + "dashboard.topbar.interfaceLabel": "翻译界面", + "dashboard.topbar.premiumAccess": "高级访问", + "dashboard.checkoutSyncError": "同步付款时出错。", + "dashboard.networkRefresh": "网络错误。请刷新页面。", + "dashboard.continueToTranslate": "继续翻译" +} diff --git a/frontend/src/lib/i18n/messages/zh/fileUploader.json b/frontend/src/lib/i18n/messages/zh/fileUploader.json new file mode 100644 index 0000000..10c4646 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/fileUploader.json @@ -0,0 +1,31 @@ +{ + "fileUploader.uploadDocument": "上传文档", + "fileUploader.uploadDesc": "拖放或点击选择文件 (Excel, Word, PowerPoint)", + "fileUploader.dropHere": "将文件拖到此处…", + "fileUploader.dragAndDrop": "将文档拖到此处", + "fileUploader.orClickBrowse": "或点击浏览", + "fileUploader.preview": "预览", + "fileUploader.translationOptions": "翻译选项", + "fileUploader.configureSettings": "配置翻译设置", + "fileUploader.targetLanguage": "目标语言", + "fileUploader.selectLanguage": "选择语言", + "fileUploader.translationProvider": "翻译服务提供商", + "fileUploader.selectProvider": "选择提供商", + "fileUploader.advancedOptions": "高级选项", + "fileUploader.translateImages": "翻译图片", + "fileUploader.translating": "翻译中…", + "fileUploader.translateDocument": "翻译文档", + "fileUploader.processing": "处理中…", + "fileUploader.translationError": "翻译错误", + "fileUploader.translationComplete": "翻译完成!", + "fileUploader.translationCompleteDesc": "您的文档已成功翻译,并保留了所有格式。", + "fileUploader.download": "下载翻译后的文档", + "fileUploader.webgpuUnsupported": "此浏览器不支持 WebGPU。请使用 Chrome 113+ 或 Edge 113+。", + "fileUploader.webllmNotLoaded": "WebLLM 模型未加载。请前往设置 > 翻译服务 加载模型。", + "fileUploader.extracting": "正在从文档中提取文本…", + "fileUploader.noTranslatable": "文档中未找到可翻译的文本", + "fileUploader.foundTexts": "找到 {count} 个要翻译的文本", + "fileUploader.translatingItem": "正在翻译 {current}/{total}: \\\"{preview}\\\"", + "fileUploader.reconstructing": "正在重建文档…", + "fileUploader.translatingLocally": "正在使用 WebLLM 本地翻译…" +} diff --git a/frontend/src/lib/i18n/messages/zh/glossaries.json b/frontend/src/lib/i18n/messages/zh/glossaries.json new file mode 100644 index 0000000..495ff16 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/glossaries.json @@ -0,0 +1,189 @@ +{ + "glossaries.yourGlossaries": "您的术语表", + "glossaries.title": "术语表与上下文", + "glossaries.description": "管理您的术语表和上下文指令,以获得更准确的翻译。", + "glossaries.createNew": "新建", + "glossaries.empty": "暂无术语表", + "glossaries.emptyDesc": "创建您的第一个术语表或加载上方的专业预设", + "glossaries.defineTerms": "术语", + "glossaries.aboutTitle": "关于术语表", + "glossaries.aboutDesc": "术语表允许您为特定术语定义准确的翻译。翻译时,术语表中的术语可确保翻译的一致性和准确性。", + "glossaries.aboutFormat": "每个术语都有一个源词和多种语言的翻译。在翻译页面选择术语表即可应用。", + "glossaries.toast.created": "术语表已创建", + "glossaries.toast.createdDesc": "术语表\\\"{name}\\\"已创建。", + "glossaries.toast.imported": "术语表已导入", + "glossaries.toast.importedDesc": "术语表\\\"{name}\\\"已导入。", + "glossaries.toast.updated": "术语表已更新", + "glossaries.toast.updatedDesc": "术语表\\\"{name}\\\"已更新。", + "glossaries.toast.deleted": "术语表已删除", + "glossaries.toast.deletedDesc": "术语表已删除。", + "glossaries.toast.error": "错误", + "glossaries.toast.errorCreate": "创建术语表失败", + "glossaries.toast.errorImport": "导入术语表失败", + "glossaries.toast.errorUpdate": "更新术语表失败", + "glossaries.toast.errorDelete": "删除术语表失败", + "glossaries.dialog.title": "新建术语表", + "glossaries.dialog.description": "为您的翻译创建术语表", + "glossaries.dialog.nameLabel": "名称", + "glossaries.dialog.namePlaceholder": "我的术语表", + "glossaries.dialog.tabTemplates": "模板", + "glossaries.dialog.tabFile": "文件", + "glossaries.dialog.tabManual": "手动", + "glossaries.dialog.cancel": "取消", + "glossaries.dialog.creating": "正在创建…", + "glossaries.dialog.importing": "正在导入…", + "glossaries.dialog.importBtn": "导入", + "glossaries.dialog.selectPrompt": "选择", + "glossaries.dialog.createBtn": "创建", + "glossaries.dialog.createEmpty": "创建空表", + "glossaries.dialog.terms": "个术语", + "glossaries.dialog.templatesDesc": "选择预定义模板", + "glossaries.dialog.templatesEmpty": "暂无可用模板", + "glossaries.dialog.dropTitle": "将 CSV 文件拖到此处", + "glossaries.dialog.dropOr": "或", + "glossaries.dialog.dropFormats": "CSV、TSV、TXT", + "glossaries.termEditor.addTerm": "添加术语", + "glossaries.termEditor.maxReached": "每个术语表最多 {max} 个术语。", + "glossaries.dialog.formatTitle": "格式", + "glossaries.dialog.formatDesc": "源语言,目标语言(每行一对)", + "glossaries.dialog.formatNote": "如检测到表头则跳过首行", + "glossaries.dialog.errorFormat": "不支持的格式", + "glossaries.dialog.errorSize": "文件过大", + "glossaries.dialog.errorEmpty": "空文件", + "glossaries.dialog.errorRead": "读取错误", + "glossaries.dialog.parsing": "正在解析…", + "glossaries.dialog.termsImported": "个术语已导入", + "glossaries.dialog.changeFile": "更换文件", + "glossaries.dialog.retry": "重试", + "glossaries.edit.title": "Modifier le glossaire", + "glossaries.edit.description": "Modifiez le nom, la paire de langues et les termes du glossaire.", + "glossaries.edit.nameLabel": "Nom du glossaire", + "glossaries.edit.namePlaceholder": "Entrez le nom du glossaire...", + "glossaries.edit.sourceLang": "Langue source", + "glossaries.edit.targetLang": "Langue cible", + "glossaries.edit.termsLabel": "Termes ({count} valides)", + "glossaries.edit.exportCsv": "Exporter CSV", + "glossaries.edit.importCsv": "Importer CSV", + "glossaries.edit.cancel": "Annuler", + "glossaries.edit.saving": "Enregistrement...", + "glossaries.edit.saveChanges": "Enregistrer les modifications", + "glossaries.edit.importFailedTitle": "Échec de l'importation", + "glossaries.edit.importFailedMaxDesc": "Le CSV contient {count} termes, le maximum est de {max}. Veuillez réduire le nombre de termes.", + "glossaries.edit.importSuccessTitle": "Importation réussie", + "glossaries.edit.importSuccessDesc": "{count} termes importés avec succès.", + "glossaries.edit.importFailedEmptyDesc": "Aucun terme valide trouvé dans le fichier CSV.", + "glossaries.edit.importFailedReadDesc": "Impossible de lire le fichier CSV.", + "glossaries.delete.title": "Supprimer le glossaire", + "glossaries.delete.description": "Êtes-vous sûr de vouloir supprimer ce glossaire ?", + "glossaries.delete.warning": "Cette action est irréversible", + "glossaries.delete.warningDesc": "Toutes les paires de termes seront définitivement supprimées.", + "glossaries.delete.cancel": "Annuler", + "glossaries.delete.deleting": "Suppression...", + "glossaries.delete.deleteBtn": "Supprimer", + "glossaries.upgrade.title": "Glossaires", + "glossaries.upgrade.description": "Personnalisez vos traductions avec une terminologie personnalisée", + "glossaries.upgrade.feature1": "Créez plusieurs glossaires", + "glossaries.upgrade.feature2": "Définissez des paires de termes source→cible", + "glossaries.upgrade.feature3": "Importez/exportez via CSV", + "glossaries.upgrade.feature4": "Appliquez aux traductions LLM", + "glossaries.upgrade.proFeatureBefore": "Les glossaires sont une fonctionnalité ", + "glossaries.upgrade.proFeatureAfter": ". Passez à un forfait supérieur pour débloquer la terminologie personnalisée.", + "glossaries.upgrade.proLabel": "Pro", + "glossaries.upgrade.upgradeBtn": "Passer à Pro", + "glossaries.loading": "Chargement...", + "glossaries.howItWorks.title": "Comment ces paramètres sont utilisés", + "glossaries.howItWorks.step1Title": "Configurez ici", + "glossaries.howItWorks.step1Desc": "Rédigez vos instructions de contexte ou créez/importez un glossaire de termes.", + "glossaries.howItWorks.step2Title": "Activez dans Traduire", + "glossaries.howItWorks.step2Desc": "Sur la page de traduction, dans la colonne de droite, sélectionnez votre glossaire.", + "glossaries.howItWorks.warning": "Les instructions de contexte s'appliquent automatiquement à toutes vos traductions IA une fois enregistrées. Les glossaires doivent être sélectionnés manuellement sur la page Traduire.", + "glossaries.howItWorks.goToTranslate": "Aller à Traduire", + "glossaries.status.unsaved": "Non enregistré", + "glossaries.status.active": "Actif · s'applique à toutes les traductions IA", + "glossaries.status.inactive": "Inactif", + "glossaries.instructions.whatForBold": "À quoi ça sert ?", + "glossaries.instructions.whatForDesc": "Ces instructions sont envoyées automatiquement à l'IA avant chaque traduction, sans que vous ayez besoin de faire quoi que ce soit sur la page Traduire. Utilisez-les pour guider le style, le registre ou la terminologie générale.", + "glossaries.instructions.example": "Exemple : « Vous traduisez des rapports financiers. Soyez formel, précis et conservez tous les chiffres. »", + "glossaries.instructions.charCount": "{count} caractères", + "glossaries.instructions.emptyHint": "Vide — aucune instruction envoyée à l'IA", + "glossaries.instructions.clearAll": "Tout effacer", + "glossaries.instructions.saving": "Enregistrement…", + "glossaries.instructions.saved": "Enregistré", + "glossaries.presets.whatForBold": "À quoi ça sert ?", + "glossaries.presets.whatForDesc": "Cliquer sur une carte crée un glossaire pré-rempli avec les termes spécialisés du domaine. Ce glossaire apparaîtra dans vos glossaires ci-dessous, et vous pourrez le sélectionner manuellement sur la page Traduire pour forcer des traductions de termes précis.", + "glossaries.presets.clickHint": "Cliquez sur une carte → glossaire créé → sélectionnez-le dans Traduire", + "glossaries.presets.creating": "Création…", + "glossaries.presets.alreadyImported": "Déjà importé", + "glossaries.presets.it.title": "IT / Logiciel", + "glossaries.presets.it.desc": "Développement, infrastructure, DevOps", + "glossaries.presets.legal.title": "Juridique / Contrats", + "glossaries.presets.legal.desc": "Droit des affaires, contentieux", + "glossaries.presets.medical.title": "Médical / Santé", + "glossaries.presets.medical.desc": "Pharmacologie, chirurgie, diagnostic", + "glossaries.presets.finance.title": "Finance / Comptabilité", + "glossaries.presets.finance.desc": "IFRS, bilans, fiscalité", + "glossaries.presets.marketing.title": "Marketing / Publicité", + "glossaries.presets.marketing.desc": "Digital, branding, analytics", + "glossaries.presets.hr.title": "RH / Ressources Humaines", + "glossaries.presets.hr.desc": "Contrats, politiques, recrutement", + "glossaries.presets.scientific.title": "Scientifique / Recherche", + "glossaries.presets.scientific.desc": "Publications, thèses, articles", + "glossaries.presets.ecommerce.title": "E-commerce / Vente", + "glossaries.presets.ecommerce.desc": "Boutiques en ligne, catalogues, CRM", + "glossaries.grid.title": "Vos", + "glossaries.grid.titleHighlight": "glossaires", + "glossaries.grid.countWithAction": "{count} glossaire({plural}) — cliquez sur une carte pour la modifier", + "glossaries.grid.emptyAction": "Créez votre premier glossaire ou importez un preset ci-dessus", + "glossaries.grid.activeTranslation": "Traduction active :", + "glossaries.grid.goToTranslate": "Aller à Traduire pour activer", + "glossaries.badge.compatible": "Compatible", + "glossaries.badge.otherTarget": "Autre cible", + "glossaries.card.editTerms": "Modifier les termes", + "glossaries.card.created": "已创建", + "glossaries.card.term": "术语", + "glossaries.card.delete": "Supprimer", + "glossaries.grid.searchPlaceholder": "Search a glossary…", + "glossaries.grid.noResults": "No results for this search.", + "glossaries.detail.backToList": "Back to glossaries", + "glossaries.detail.save": "Save", + "glossaries.detail.savedTitle": "Saved", + "glossaries.detail.savedDesc": "The glossary has been updated.", + "glossaries.detail.settingsTitle": "Settings", + "glossaries.detail.sourceLang": "Source language", + "glossaries.detail.targetLang": "Target language", + "glossaries.detail.termsTitle": "Terms", + "glossaries.detail.terms": "terms", + "glossaries.detail.searchTerms": "Filter…", + "glossaries.detail.noTerms": "No terms yet.", + "glossaries.detail.addFirstTerm": "Add the first term", + "glossaries.detail.addTerm": "Add a term", + "glossaries.detail.maxReached": "Maximum limit reached", + "glossaries.detail.source": "Source", + "glossaries.detail.target": "Target", + "glossaries.detail.sourcePlaceholder": "source term", + "glossaries.detail.targetPlaceholder": "target term", + "glossaries.detail.csvTitle": "CSV", + "glossaries.detail.csvDesc": "Export your terms as CSV or import new ones (replaces the current list).", + "glossaries.detail.export": "Export", + "glossaries.detail.import": "Import", + "glossaries.detail.dangerTitle": "Danger zone", + "glossaries.detail.dangerDesc": "Deletion is permanent. All associated terms will be lost.", + "glossaries.detail.deleteGlossary": "Delete this glossary", + "glossaries.detail.confirmDelete": "Confirm deletion?", + "glossaries.detail.confirm": "Confirm", + "glossaries.detail.cancel": "Cancel", + "glossaries.detail.sourceLangNote": "'The original source is in French. For other languages, we read the term's translations field (if available).'", + "glossaries.detail.sourceLocked": "fixed", + "glossaries.detail.sourceLockedNote": "Templates only store the source in French. Multilingual source is on the roadmap.", + "glossaries.detail.targetLangNote": "Pick a language to see the matching translations, or « Multilingual » for the default value.", + "glossaries.detail.notFoundTitle": "Glossary not found", + "glossaries.detail.notFoundDesc": "This glossary does not exist or you don't have access to it.", + "glossaries.detail.maxTermsTitle": "Limit reached", + "glossaries.detail.maxTermsDesc": "Maximum {max} terms per glossary.", + "glossaries.detail.importEmptyTitle": "Empty file", + "glossaries.detail.importEmptyDesc": "No terms detected in this file.", + "glossaries.detail.importedTitle": "Imported", + "glossaries.detail.importedDesc": "{count} terms imported.", + "glossaries.detail.importErrorTitle": "Read error", + "glossaries.detail.importErrorDesc": "Unable to read the file." +} diff --git a/frontend/src/lib/i18n/messages/zh/index.ts b/frontend/src/lib/i18n/messages/zh/index.ts new file mode 100644 index 0000000..638d0d9 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/index.ts @@ -0,0 +1,56 @@ +// Auto-generated by scripts/generate_i18n_index.py +// Merges all namespace JSON files for locale "zh". + +import admin from "./admin.json"; +import apiKeys from "./apiKeys.json"; +import auth from "./auth.json"; +import checkout from "./checkout.json"; +import common from "./common.json"; +import context from "./context.json"; +import cookieConsent from "./cookieConsent.json"; +import dashboard from "./dashboard.json"; +import fileUploader from "./fileUploader.json"; +import glossaries from "./glossaries.json"; +import landing from "./landing.json"; +import langSelector from "./langSelector.json"; +import layout from "./layout.json"; +import login from "./login.json"; +import memento from "./memento.json"; +import pricing from "./pricing.json"; +import profile from "./profile.json"; +import providerSelector from "./providerSelector.json"; +import providerTheme from "./providerTheme.json"; +import register from "./register.json"; +import services from "./services.json"; +import settings from "./settings.json"; +import translate from "./translate.json"; +import translateComplete from "./translateComplete.json"; + +const messages: Record = { + ...admin, + ...apiKeys, + ...auth, + ...checkout, + ...common, + ...context, + ...cookieConsent, + ...dashboard, + ...fileUploader, + ...glossaries, + ...landing, + ...langSelector, + ...layout, + ...login, + ...memento, + ...pricing, + ...profile, + ...providerSelector, + ...providerTheme, + ...register, + ...services, + ...settings, + ...translate, + ...translateComplete, +}; + +export default messages; diff --git a/frontend/src/lib/i18n/messages/zh/landing.json b/frontend/src/lib/i18n/messages/zh/landing.json new file mode 100644 index 0000000..dd227c9 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/landing.json @@ -0,0 +1,146 @@ +{ + "landing.nav.why": "为什么选择我们", + "landing.nav.formats": "支持格式", + "landing.nav.pricing": "定价", + "landing.nav.login": "登录", + "landing.nav.startFree": "免费开始", + "landing.hero.tag": "专业文档AI", + "landing.hero.titleLine1": "翻译您的文档。", + "landing.hero.titleLine2": "完美保留格式。", + "landing.hero.description": "唯一能够保留SmartArt、图表、目录、形状和复杂布局的翻译工具——与原始格式完全一致。", + "landing.hero.ctaMain": "免费开始 — 每月2份文档", + "landing.hero.ctaSec": "查看方案", + "landing.hero.deleted": "文件60分钟后删除", + "landing.hero.noHidden": "无隐藏费用", + "landing.hero.preview": "付款前预览", + "landing.hero.formattedOk": "格式正常", + "landing.hero.aiActive": "AI翻译已启用", + "landing.steps.title": "如何使用?", + "landing.steps.subtitle": "三个步骤,零格式损失。", + "landing.steps.step1.num": "01", + "landing.steps.step1.title": "上传文件", + "landing.steps.step1.desc": "拖放您的Excel、Word、PowerPoint或PDF文档。", + "landing.steps.step2.num": "02", + "landing.steps.step2.title": "选择语言和引擎", + "landing.steps.step2.desc": "选择目标语言和翻译引擎——经典引擎或上下文感知AI。", + "landing.steps.step3.num": "03", + "landing.steps.step3.title": "下载结果", + "landing.steps.step3.desc": "获取与原始格式完全一致的翻译文档。", + "landing.features.tag": "AI翻译引擎", + "landing.features.title": "理解您专业的翻译", + "landing.features.description": "我们的AI模型分析上下文、尊重您的术语,甚至翻译图片中的文字。", + "landing.features.context.title": "行业上下文", + "landing.features.context.desc": "描述您的行业,获得定制化翻译,而非通用翻译。", + "landing.features.glossary.title": "行业术语表", + "landing.features.glossary.desc": "定义您的专业术语。CTA保持为「空气处理机组」,而非「行动号召」。", + "landing.features.vision.title": "图像识别", + "landing.features.vision.desc": "嵌入在图片、图表和图形中的文字会被检测并翻译。", + "landing.features.demo.source": "原文(FR)", + "landing.features.demo.google": "Google翻译", + "landing.features.demo.ours": "我们的AI", + "landing.layout.title": "您的格式,", + "landing.layout.title2": "完美保留", + "landing.layout.subtitle": "其他翻译工具会破坏您的排版。我们不会。", + "landing.layout.p1.title": "SmartArt和图表", + "landing.layout.p1.desc": "组织结构图、流程图、层级图——全部精确翻译。", + "landing.layout.p2.title": "目录", + "landing.layout.p2.desc": "目录条目、页码和交叉引用正确更新。", + "landing.layout.p3.title": "图表和图形", + "landing.layout.p3.desc": "标题、轴标签、图例和系列名称——全部翻译。", + "landing.layout.p4.title": "形状和文本框", + "landing.layout.p4.desc": "矩形、圆角块、标注——全面本地化。", + "landing.layout.p5.title": "页眉和页脚", + "landing.layout.p5.desc": "页眉、页脚和脚注绝不会被遗漏。", + "landing.layout.p6.title": "130+种语言", + "landing.layout.p6.desc": "Google翻译、DeepL及专业级AI引擎。", + "landing.formats.title": "每种格式,", + "landing.formats.title2": "每个元素", + "landing.formats.subtitle": "我们翻译其他工具遗漏的内容。您的企业值得拥有完美无瑕的文档。", + "landing.formats.word.name": "Word", + "landing.formats.word.i1": "段落和标题", + "landing.formats.word.i2": "表格和图表", + "landing.formats.word.i3": "SmartArt图表", + "landing.formats.word.i4": "目录", + "landing.formats.word.i5": "页眉和页脚", + "landing.formats.word.i6": "形状和文本框", + "landing.formats.word.i7": "脚注和尾注", + "landing.formats.excel.name": "Excel", + "landing.formats.excel.i1": "单元格值", + "landing.formats.excel.i2": "工作表名称", + "landing.formats.excel.i3": "图表和标签", + "landing.formats.excel.i4": "页眉和页脚", + "landing.formats.excel.i5": "合并单元格保留", + "landing.formats.pptx.name": "PowerPoint", + "landing.formats.pptx.i1": "幻灯片文本和备注", + "landing.formats.pptx.i2": "图表和图形", + "landing.formats.pptx.i3": "形状和文本框", + "landing.formats.pptx.i4": "母版布局", + "landing.formats.pptx.i5": "动画保留", + "landing.formats.pdf.name": "PDF", + "landing.formats.pdf.i1": "基于文本的PDF", + "landing.formats.pdf.i2": "布局保留", + "landing.formats.pdf.i3": "图片保持在原位", + "landing.formats.pdf.i4": "表格保持", + "landing.formats.pdf.i5": "输出为DOCX或PDF", + "landing.pricing.title": "简单透明的定价", + "landing.pricing.subtitle": "所见即所付。无隐藏费用。", + "landing.pricing.monthly": "月付", + "landing.pricing.annual": "年付", + "landing.pricing.bestValue": "最受欢迎", + "landing.pricing.month": "/月", + "landing.pricing.footer": "显示的价格就是您支付的价格。翻译后无任何隐藏费用。", + "landing.pricing.starter.name": "Starter", + "landing.pricing.starter.desc": "适合个人和小型项目", + "landing.pricing.starter.f1": "每月50份文档", + "landing.pricing.starter.f2": "每份文档最多50页", + "landing.pricing.starter.f3": "Google翻译 + DeepL", + "landing.pricing.starter.f4": "文件最大10 MB", + "landing.pricing.starter.cta": "立即开始", + "landing.pricing.pro.name": "Pro", + "landing.pricing.pro.desc": "适合专业用户", + "landing.pricing.pro.f1": "每月200份文档", + "landing.pricing.pro.f2": "每份文档最多200页", + "landing.pricing.pro.f3": "AI翻译", + "landing.pricing.pro.f4": "包含Google + DeepL", + "landing.pricing.pro.f5": "自定义术语表和提示词", + "landing.pricing.pro.f6": "优先支持", + "landing.pricing.pro.cta": "试用Pro", + "landing.pricing.business.name": "企业版", + "landing.pricing.business.desc": "适合大批量需求的团队", + "landing.pricing.business.f1": "每月1,000份文档", + "landing.pricing.business.f2": "每份文档最多500页", + "landing.pricing.business.f3": "高级AI(Claude)", + "landing.pricing.business.f4": "所有供应商 + API", + "landing.pricing.business.f5": "Webhook和自动化", + "landing.pricing.business.f6": "5个团队席位", + "landing.pricing.business.cta": "联系我们", + "landing.cta.title": "30秒开始翻译", + "landing.cta.subtitle": "无需信用卡。立即免费试用,让您的多语言文档重获新生。", + "landing.cta.button": "创建免费账户", + "landing.cta.secure": "AES-256加密保护", + "landing.footer.desc": "智能文档翻译专家。我们将排版的艺术与上下文AI的科学完美融合。", + "landing.footer.product": "产品", + "landing.footer.resources": "资源", + "landing.footer.legal": "法律", + "landing.footer.rights": "© 2026 Wordly.art — 保留所有权利。", + "landing.hero.contextEngine": "检测到翻译:HVAC 系统技术维护术语...", + "landing.hero.liveAnalysis": "实时分析", + "landing.hero.termsDetected": "个术语已检测", + "landing.steps.process": "流程", + "landing.translate.newProject": "新项目", + "landing.translate.title": "翻译文档", + "landing.translate.subtitle": "导入文件并选择目标语言", + "landing.translate.sourceDocument": "源文档", + "landing.translate.configuration": "配置", + "landing.translate.sourceLang": "源语言", + "landing.translate.targetLang": "目标语言", + "landing.translate.provider": "提供商", + "landing.translate.startTranslation": "开始翻译", + "landing.translate.zeroRetention": "零保留", + "landing.translate.filesDeleted": "处理后删除文件", + "landing.translate.dropHere": "拖放到此处", + "landing.translate.supportedFormats": "支持 DOCX, XLSX, PPTX 或 PDF 文件", + "landing.translate.aiAnalysis": "AI 分析中", + "landing.translate.processing": "正在处理", + "landing.translate.preservingLayout": "正在保留您的排版" +} diff --git a/frontend/src/lib/i18n/messages/zh/langSelector.json b/frontend/src/lib/i18n/messages/zh/langSelector.json new file mode 100644 index 0000000..df0490e --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/langSelector.json @@ -0,0 +1,7 @@ +{ + "langSelector.search": "搜索…", + "langSelector.noResults": "无结果", + "langSelector.source": "源", + "langSelector.target": "目标", + "langSelector.swap": "交换" +} diff --git a/frontend/src/lib/i18n/messages/zh/layout.json b/frontend/src/lib/i18n/messages/zh/layout.json new file mode 100644 index 0000000..96e03f1 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/layout.json @@ -0,0 +1,5 @@ +{ + "layout.nav.apiAccess": "API 访问", + "layout.footer.terms": "条款", + "layout.footer.privacy": "隐私" +} diff --git a/frontend/src/lib/i18n/messages/zh/login.json b/frontend/src/lib/i18n/messages/zh/login.json new file mode 100644 index 0000000..4c0d999 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/login.json @@ -0,0 +1,6 @@ +{ + "login.orContinueWith": "或使用电子邮件继续", + "login.google.connecting": "连接中…", + "login.google.errorGeneric": "Google 登录时出现问题。", + "login.google.errorFailed": "Google 登录失败。请重试。" +} diff --git a/frontend/src/lib/i18n/messages/zh/memento.json b/frontend/src/lib/i18n/messages/zh/memento.json new file mode 100644 index 0000000..6176125 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/memento.json @@ -0,0 +1,6 @@ +{ + "memento.title": "探索 Momento", + "memento.slogan": "Momento 不仅仅是一个笔记应用。它是一个智能生态系统,利用 6 个 AI 代理和先进的语义搜索,实时连接、分析和发展您的想法。", + "memento.ctaFree": "免费开始", + "memento.ctaMore": "了解更多" +} diff --git a/frontend/src/lib/i18n/messages/zh/pricing.json b/frontend/src/lib/i18n/messages/zh/pricing.json new file mode 100644 index 0000000..75d5e08 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/pricing.json @@ -0,0 +1,151 @@ +{ + "pricing.nav.back": "返回", + "pricing.nav.home": "首页", + "pricing.nav.mySubscription": "我的订阅", + "pricing.header.badge": "AI 模型已更新 — 2026年3月", + "pricing.header.title": "满足各种需求的方案", + "pricing.header.subtitle": "翻译 Word、Excel 和 PowerPoint 文档,同时保留原始排版。无需 API 密钥。", + "pricing.billing.monthly": "月付", + "pricing.billing.yearly": "年付", + "pricing.plans.free.name": "免费", + "pricing.plans.starter.name": "入门版", + "pricing.plans.pro.name": "专业版", + "pricing.plans.business.name": "企业版", + "pricing.plans.enterprise.name": "旗舰版", + "pricing.plans.free.description": "非常适合体验应用", + "pricing.plans.starter.description": "面向个人和小型项目", + "pricing.plans.pro.description": "面向专业人士和成长中的团队", + "pricing.plans.business.description": "面向团队和组织", + "pricing.plans.enterprise.description": "为大型组织提供定制解决方案", + "pricing.plans.pro.highlight": "最受欢迎", + "pricing.plans.pro.badge": "热门", + "pricing.plans.enterprise.badge": "按需报价", + "pricing.plans.free.feat1": "每月 5 份文档", + "pricing.plans.free.feat2": "每份文档最多 15 页", + "pricing.plans.free.feat3": "包含 Google 翻译", + "pricing.plans.free.feat4": "支持所有语言(130+)", + "pricing.plans.free.feat5": "社区支持", + "pricing.plans.starter.feat1": "每月 50 份文档", + "pricing.plans.starter.feat2": "每份文档最多 50 页", + "pricing.plans.starter.feat3": "Google 翻译 + DeepL", + "pricing.plans.starter.feat4": "文件最大 10 MB", + "pricing.plans.starter.feat5": "邮件支持", + "pricing.plans.starter.feat6": "30 天历史记录", + "pricing.plans.pro.feat1": "每月 200 份文档", + "pricing.plans.pro.feat2": "每份文档最多 200 页", + "pricing.plans.pro.feat3": "Essential AI翻译", + "pricing.plans.pro.feat4": "Google 翻译 + DeepL", + "pricing.plans.pro.feat5": "文件最大 25 MB", + "pricing.plans.pro.feat6": "自定义术语表", + "pricing.plans.pro.feat7": "优先支持", + "pricing.plans.pro.feat8": "90 天历史记录", + "pricing.plans.business.feat1": "每月 1,000 份文档", + "pricing.plans.business.feat2": "每份文档最多 500 页", + "pricing.plans.business.feat3": "基础 + 高级 AI(Claude Haiku)", + "pricing.plans.business.feat4": "所有翻译服务商", + "pricing.plans.business.feat5": "文件最大 50 MB", + "pricing.plans.business.feat6": "API 访问(每月 10,000 次调用)", + "pricing.plans.business.feat7": "通知 Webhook", + "pricing.plans.business.feat8": "专属支持", + "pricing.plans.business.feat9": "1 年历史记录", + "pricing.plans.business.feat10": "高级分析", + "pricing.plans.enterprise.feat1": "无限文档", + "pricing.plans.enterprise.feat2": "所有 AI 模型(GPT-5、Claude Opus 4.6…)", + "pricing.plans.enterprise.feat3": "本地部署或专属云", + "pricing.plans.enterprise.feat4": "99.9% SLA 保障", + "pricing.plans.enterprise.feat5": "24/7 专属支持", + "pricing.plans.enterprise.feat6": "白标(White-label)", + "pricing.plans.enterprise.feat7": "无限团队", + "pricing.plans.enterprise.feat8": "定制集成", + "pricing.card.onRequest": "按需报价", + "pricing.card.free": "免费", + "pricing.card.perMonth": "/月", + "pricing.card.billedYearly": "按年计费 {price} €", + "pricing.card.documents": "文档", + "pricing.card.pagesMax": "最大页数", + "pricing.card.aiTranslation": "AI 翻译", + "pricing.card.unlimited": "无限", + "pricing.card.perMonthStat": "/ 月", + "pricing.card.perDoc": "页 / 文档", + "pricing.card.aiEssential": "基础版", + "pricing.card.aiEssentialPremium": "基础版 + 高级版", + "pricing.card.aiCustom": "定制", + "pricing.card.myPlan": "我的方案", + "pricing.card.managePlan": "管理方案", + "pricing.card.startFree": "免费开始", + "pricing.card.contactUs": "联系我们", + "pricing.card.choosePlan": "选择此方案", + "pricing.card.processing": "处理中…", + "pricing.comparison.title": "详细对比", + "pricing.comparison.subtitle": "各方案包含的所有功能", + "pricing.comparison.feature": "功能", + "pricing.comparison.docsPerMonth": "文档 / 月", + "pricing.comparison.pagesMaxPerDoc": "最大页数 / 文档", + "pricing.comparison.maxFileSize": "最大文件大小", + "pricing.comparison.googleTranslation": "Google 翻译", + "pricing.comparison.deepl": "DeepL", + "pricing.comparison.aiEssential": "基础 AI 翻译", + "pricing.comparison.aiPremium": "高级 AI 翻译", + "pricing.comparison.apiAccess": "API 访问", + "pricing.comparison.priorityProcessing": "优先处理", + "pricing.comparison.support": "支持", + "pricing.comparison.support.community": "社区", + "pricing.comparison.support.email": "邮件", + "pricing.comparison.support.priority": "优先", + "pricing.comparison.support.dedicated": "专属", + "pricing.comparison.mb": "MB", + "pricing.credits.title": "额外额度", + "pricing.credits.subtitle": "需要更多?单独购买额度,无需订阅。", + "pricing.credits.perPage": "1 额度 = 1 翻译页。", + "pricing.credits.bestValue": "最划算", + "pricing.credits.unit": "额度", + "pricing.credits.centsPerCredit": "分 / 额度", + "pricing.credits.buy": "购买", + "pricing.trust.encryption.title": "端到端加密", + "pricing.trust.encryption.sub": "TLS 1.3 + AES-256 静态加密", + "pricing.trust.languages.title": "130+ 种语言", + "pricing.trust.languages.sub": "包括阿拉伯语、波斯语、希伯来语(RTL)", + "pricing.trust.parallel.title": "并行处理", + "pricing.trust.parallel.sub": "超快多线程 AI", + "pricing.trust.availability.title": "7×24 小时可用", + "pricing.trust.availability.sub": "99.9% 可用性保障", + "pricing.aiModels.title": "我们的 AI 模型 — 2026年3月", + "pricing.aiModels.essential.title": "基础 AI 翻译", + "pricing.aiModels.essential.plan": "专业版方案", + "pricing.aiModels.essential.descPrefix": "基于", + "pricing.aiModels.essential.descSuffix": "— 2026 年最具性价比的 AI 模型。质量媲美前沿模型,成本仅为其一小部分。", + "pricing.aiModels.essential.modelName": "Essential AI模型", + "pricing.aiModels.essential.context": "163K 上下文 Token", + "pricing.aiModels.essential.value": "性价比极佳", + "pricing.aiModels.premium.title": "高级 AI 翻译", + "pricing.aiModels.premium.plan": "企业版方案", + "pricing.aiModels.premium.descPrefix": "基于", + "pricing.aiModels.premium.descSuffix": "Anthropic 出品 — 在法律、医疗和复杂技术文档方面表现精准。", + "pricing.aiModels.premium.context": "200K 上下文 Token", + "pricing.aiModels.premium.precision": "最高精度", + "pricing.faq.title": "常见问题", + "pricing.faq.q1": "我可以随时更换方案吗?", + "pricing.faq.a1": "可以。升级立即生效并按比例计费。降级在当前周期结束时生效。", + "pricing.faq.q2": "什么是「基础 AI 翻译」?", + "pricing.faq.a2": "这是我们的AI引擎。它能理解文档上下文,保留排版,并比传统翻译更好地处理技术术语。", + "pricing.faq.q3": "基础 AI 和高级 AI 有什么区别?", + "pricing.faq.a3": "Essential AI使用优化模型(性价比极佳)。Premium AI使用Anthropic的Claude 3.5 Haiku,在法律、医学和复杂技术文档上更准确。", + "pricing.faq.q4": "翻译后文档会被保留吗?", + "pricing.faq.a4": "翻译文件根据您的方案保留(入门版 30 天、专业版 90 天、企业版 1 年)。存储和传输过程中均已加密。", + "pricing.faq.q5": "超过月度配额会怎样?", + "pricing.faq.a5": "You can buy additional credits individually, or upgrade your plan.", + "pricing.faq.q6": "付费方案有免费试用吗?", + "pricing.faq.a6": "免费方案永久有效且无需信用卡。专业版和企业版方案请联系我们获取 14 天试用。", + "pricing.faq.q7": "支持哪些文件格式?", + "pricing.faq.a7": "Word(.docx)、Excel(.xlsx/.xls)、PowerPoint(.pptx),即将支持 PDF。所有方案支持相同的格式。", + "pricing.cta.title": "准备好开始了吗?", + "pricing.cta.subtitle": "免费开始,无需信用卡。需要时再升级。", + "pricing.cta.createAccount": "创建免费账户", + "pricing.cta.login": "登录", + "pricing.toast.demo": "演示模式 — Stripe 尚未配置。在生产环境中,您将被重定向至支付页面以激活 {planId} 方案。", + "pricing.toast.networkError": "网络错误,请重试。", + "pricing.toast.paymentError": "创建支付时出错。", + "pricing.dashboard": "仪表板", + "pricing.okSymbol": "✓", + "pricing.errSymbol": "✕" +} diff --git a/frontend/src/lib/i18n/messages/zh/profile.json b/frontend/src/lib/i18n/messages/zh/profile.json new file mode 100644 index 0000000..c23f86c --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/profile.json @@ -0,0 +1,58 @@ +{ + "profile.header.title": "我的资料", + "profile.header.subtitle": "管理您的账户和偏好设置。", + "profile.tabs.account": "账户", + "profile.tabs.subscription": "订阅", + "profile.tabs.preferences": "偏好设置", + "profile.account.user": "用户", + "profile.account.memberSince": "注册时间", + "profile.plan.label": "套餐", + "profile.plan.free": "Free", + "profile.plan.starter": "Starter", + "profile.plan.pro": "Pro", + "profile.plan.business": "Business", + "profile.plan.enterprise": "Enterprise", + "profile.plan.pricePerMonth": "{price} €/月", + "profile.subscription.canceling": "取消中", + "profile.subscription.active": "有效", + "profile.subscription.unknown": "未知", + "profile.subscription.accessUntil": "访问截止日期", + "profile.subscription.renewalOn": "续费日期", + "profile.subscription.upgradePlan": "升级到付费套餐", + "profile.subscription.changePlan": "更改套餐", + "profile.subscription.manageBilling": "管理账单", + "profile.subscription.billingUnavailable": "账单门户不可用。", + "profile.subscription.billingError": "访问账单门户时出错。", + "profile.subscription.cancelSuccess": "订阅已取消。您可以继续使用至本期结束。", + "profile.subscription.cancelError": "取消时出错。", + "profile.subscription.networkError": "网络错误。", + "profile.usage.title": "本月使用量", + "profile.usage.resetOn": "重置日期", + "profile.usage.documents": "文档", + "profile.usage.pages": "页数", + "profile.usage.extraCredits": "额外额度", + "profile.usage.extraCreditsPlural": "额外额度", + "profile.usage.quotaReached": "配额已用完", + "profile.usage.quotaReachedDesc": "升级到更高套餐以继续使用。", + "profile.usage.unlockMore": "升级付费套餐以获取更多翻译。", + "profile.usage.viewPlans": "查看套餐", + "profile.usage.includedInPlan": "已包含在您的套餐中", + "profile.danger.title": "危险区域", + "profile.danger.description": "取消将在当前周期结束时生效。在此之前您可以继续使用。", + "profile.danger.confirm": "确定要继续吗?此操作不可撤销。", + "profile.danger.confirmCancel": "确认取消", + "profile.danger.cancelSubscription": "取消我的订阅", + "profile.danger.keep": "不,保留", + "profile.prefs.interfaceLang": "界面语言", + "profile.prefs.interfaceLangDesc": "语言会根据您的浏览器自动检测。您也可以手动更改。", + "profile.prefs.defaultTargetLang": "默认目标语言", + "profile.prefs.selectLanguage": "选择语言", + "profile.prefs.defaultTargetLangDesc": "翻译时将自动选择此语言。", + "profile.prefs.save": "保存", + "profile.prefs.theme": "主题", + "profile.prefs.themeDesc": "选择界面外观", + "profile.prefs.cache": "缓存", + "profile.prefs.cacheDesc": "清除本地缓存可以修复一些显示问题。", + "profile.prefs.clearing": "清除中...", + "profile.prefs.clearCache": "清除缓存" +} diff --git a/frontend/src/lib/i18n/messages/zh/providerSelector.json b/frontend/src/lib/i18n/messages/zh/providerSelector.json new file mode 100644 index 0000000..28c1ec0 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/providerSelector.json @@ -0,0 +1,7 @@ +{ + "providerSelector.noClassic": "没有可用的标准翻译器。", + "providerSelector.noLlm": "未配置 AI 模型。", + "providerSelector.costOne": "费用:每页 1 积分", + "providerSelector.costFive": "费用:每页 5 积分(高级系数)", + "providerSelector.unlockContextual": "为您的整个文档解锁高级上下文翻译。" +} diff --git a/frontend/src/lib/i18n/messages/zh/providerTheme.json b/frontend/src/lib/i18n/messages/zh/providerTheme.json new file mode 100644 index 0000000..00c20b7 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/providerTheme.json @@ -0,0 +1,29 @@ +{ + "providerTheme.deepseek.badge": "基础", + "providerTheme.deepseek.subBadge": "技术与经济", + "providerTheme.deepseek.desc": "超精准且经济的翻译,非常适合技术文档和代码。", + "providerTheme.openai.badge": "高级", + "providerTheme.openai.subBadge": "高保真", + "providerTheme.openai.desc": "全球 AI 标准。最大化的文本一致性和严格的风格尊重。", + "providerTheme.minimax.badge": "高级", + "providerTheme.minimax.subBadge": "性能", + "providerTheme.minimax.desc": "惊人的执行速度和对复杂结构的出色理解。", + "providerTheme.openrouter.badge": "快速", + "providerTheme.openrouter.subBadge": "多模型", + "providerTheme.openrouter.desc": "统一访问为翻译优化的最佳开源模型。", + "providerTheme.openrouter_premium.badge": "超级", + "providerTheme.openrouter_premium.subBadge": "最大上下文", + "providerTheme.openrouter_premium.desc": "由尖端模型(GPT-4o、Claude Sonnet 4.6)辅助,适用于长文档。", + "providerTheme.zai.badge": "专业", + "providerTheme.zai.subBadge": "金融与法律", + "providerTheme.zai.desc": "针对苛刻的业务术语(法律、金融)进行了微调的模型。", + "providerTheme.default.badge": "现代", + "providerTheme.default.subBadge": "AI 推理", + "providerTheme.default.desc": "大型语言模型 (LLM) 翻译,具有高级语义分析。", + "providerTheme.classic.google.label": "Google 翻译", + "providerTheme.classic.google.desc": "覆盖 130 多种语言的超快速翻译。建议用于一般流程。", + "providerTheme.classic.deepl.label": "DeepL Pro", + "providerTheme.classic.deepl.desc": "以流畅和自然的措辞著称的高精度翻译。", + "providerTheme.classic.google_cloud.label": "Google Cloud API", + "providerTheme.classic.google_cloud.desc": "针对处理大量文档进行优化的专业云端引擎。" +} diff --git a/frontend/src/lib/i18n/messages/zh/register.json b/frontend/src/lib/i18n/messages/zh/register.json new file mode 100644 index 0000000..a5142ed --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/register.json @@ -0,0 +1,29 @@ +{ + "register.title": "创建账户", + "register.subtitle": "免费开始翻译", + "register.error.failed": "注册失败", + "register.name.label": "姓名", + "register.name.placeholder": "您的姓名", + "register.name.error": "姓名至少需要 2 个字符", + "register.email.label": "电子邮箱", + "register.email.placeholder": "you@example.com", + "register.email.error": "无效的邮箱地址", + "register.password.label": "密码", + "register.password.error": "密码至少需要 8 个字符,包含大写字母、小写字母和数字", + "register.password.show": "显示密码", + "register.password.hide": "隐藏密码", + "register.password.strengthLabel": "强度:", + "register.password.strength.weak": "弱", + "register.password.strength.medium": "中", + "register.password.strength.strong": "强", + "register.confirmPassword.label": "确认密码", + "register.confirmPassword.error": "两次输入的密码不一致", + "register.confirmPassword.show": "显示", + "register.confirmPassword.hide": "隐藏", + "register.submit.creating": "正在创建账户...", + "register.submit.create": "创建我的账户", + "register.hasAccount": "已有账户?", + "register.login": "登录", + "register.terms.prefix": "创建账户即表示您接受我们的", + "register.terms.link": "服务条款" +} diff --git a/frontend/src/lib/i18n/messages/zh/services.json b/frontend/src/lib/i18n/messages/zh/services.json new file mode 100644 index 0000000..0f3501d --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/services.json @@ -0,0 +1,14 @@ +{ + "services.title": "翻译服务提供商", + "services.subtitle": "服务提供商由管理员配置。您可以查看当前账户可用的提供商。", + "services.loading": "正在加载提供商...", + "services.noProviders": "当前没有配置任何提供商。请联系管理员。", + "services.classic": "经典翻译", + "services.llmPro": "LLM · 上下文感知 (Pro)", + "services.available": "可用", + "services.model": "模型", + "services.adminOnly.title": "提供商配置仅限管理员", + "services.adminOnly.desc": "API 密钥、模型选择和提供商激活由管理员在管理面板中管理。您无需输入 API 密钥。", + "services.fallback.google.label": "Google 翻译", + "services.fallback.google.desc": "快速翻译,130 多种语言" +} diff --git a/frontend/src/lib/i18n/messages/zh/settings.json b/frontend/src/lib/i18n/messages/zh/settings.json new file mode 100644 index 0000000..ca5ac99 --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/settings.json @@ -0,0 +1,20 @@ +{ + "settings.title": "设置", + "settings.subtitle": "通用应用配置", + "settings.formats.title": "支持的格式", + "settings.formats.subtitle": "您可以翻译的文档类型", + "settings.formats.formulas": "公式", + "settings.formats.styles": "样式", + "settings.formats.images": "图片", + "settings.formats.headers": "页眉", + "settings.formats.tables": "表格", + "settings.formats.slides": "幻灯片", + "settings.formats.notes": "备注", + "settings.cache.title": "缓存", + "settings.cache.desc": "清除本地缓存可以修复一些显示问题。", + "settings.cache.clearing": "清除中...", + "settings.cache.clear": "清除缓存", + "settings.formats.excel.name": "Excel", + "settings.formats.word.name": "Word", + "settings.formats.powerpoint.name": "PowerPoint" +} diff --git a/frontend/src/lib/i18n/messages/zh/translate.json b/frontend/src/lib/i18n/messages/zh/translate.json new file mode 100644 index 0000000..12b50cb --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/translate.json @@ -0,0 +1,92 @@ +{ + "translate.mode.label": "Mode de traduction", + "translate.mode.classic": "Classique", + "translate.mode.classicDesc": "Rapide", + "translate.mode.proLlm": "Pro LLM", + "translate.mode.proLlmDesc": "Contextuel", + "translate.mode.tooltip": "Passez à Pro pour la traduction LLM", + "translate.mode.upgradeLink": "Passer à Pro", + "translate.mode.upgradeDesc": "pour des traductions alimentées par LLM", + "translate.glossary.title": "术语表", + "translate.glossary.select": "选择术语表", + "translate.glossary.none": "无", + "translate.glossary.terms": "个术语", + "translate.glossary.proOnly": "升级到Pro以使用术语表", + "translate.glossary.myGlossaries": "我的术语表", + "translate.glossary.fromTemplate": "从模板创建", + "translate.glossary.noGlossaryForPair": "无术语表", + "translate.glossary.noGlossaries": "无术语表", + "translate.glossary.loading": "加载中...", + "translate.glossary.classicMode": "无术语表的中性引擎(仅AI)", + "translate.glossary.selectPlaceholder": "选择术语表...", + "translate.glossary.multilingual": "多语言", + "translate.glossary.noGlossaryAvailable": "无可用术语表", + "translate.glossary.filterByLang": "按语言筛选", + "translate.glossary.active": "启用", + "translate.glossary.inactive": "未启用", + "translate.glossary.availableTemplates": "可用模板", + "translate.glossary.importing": "导入中...", + "translate.glossary.imported": "(已导入)", + "translate.glossary.noGlossaryForSource": "源语言无术语表或模板", + "translate.glossary.createGlossary": "创建术语表", + "translate.glossary.showAll": "显示所有术语表", + "translate.glossary.activePreview": "活跃匹配预览:", + "translate.glossary.total": "总计", + "translate.glossary.moreTerms": "其他术语", + "translate.glossary.noTerms": "此术语表中没有术语。", + "translate.glossary.sourceTerm": "源术语", + "translate.glossary.translation": "翻译", + "translate.glossary.addTerm": "添加术语", + "translate.glossary.disabledMode": "无术语表应用的中性引擎", + "translate.glossary.addTermError": "添加术语时出错", + "translate.glossary.networkError": "网络错误", + "translate.glossary.importFailed": "导入失败 ({status})", + "translate.glossary.helpText": "术语表强制精确的术语翻译。请选择源语言与文档原始语言匹配的术语表。", + "translate.glossary.sourceWarning": "注意:此术语表使用源语言", + "translate.glossary.sourceWarningBut": "但您的文档配置为", + "translate.glossary.targetWarning": "目标不匹配:此术语表旨在翻译为", + "translate.glossary.targetWarningBut": "但您的文档目标为", + "translate.glossary.targetWarningEnd": "术语可能不相关。", + "translate.header.processing": "正在处理", + "translate.header.aiActive": "AI 分析已激活", + "translate.header.aiActiveDesc": "您的布局正在由我们的上下文引擎保留。", + "translate.header.completed": "已完成", + "translate.header.completedTitle": "翻译完成", + "translate.header.proSpace": "专业版空间", + "translate.header.translateDoc": "翻译文档", + "translate.header.translateDocDesc": "通过我们超高保真度翻译引擎保留原始布局。", + "translate.upload.nativeFormat": "原生格式", + "translate.fileType.word": "Word (.docx)", + "translate.fileType.excel": "Excel (.xlsx)", + "translate.fileType.slides": "幻灯片 (.pptx)", + "translate.fileType.pdf": "PDF (.pdf)", + "translate.startTranslation": "开始翻译", + "translate.submit": "提交中…", + "translate.chooseTargetLang": "请选择目标语言", + "translate.pleaseLoadFile": "请先上传文件", + "translate.contextEngineActive": "上下文引擎已激活", + "translate.phase1": "阶段 1:初始化", + "translate.phase2": "阶段 2:上下文重建", + "translate.stat.segments": "段落", + "translate.stat.precision": "精度", + "translate.stat.speedLabel": "速度", + "translate.stat.turbo": "极速", + "translate.stat.time": "时间", + "translate.complete.masterQuality": "✓ 大师级品质", + "translate.download": "下载", + "translate.newTranslation": "+ 新建翻译", + "translate.failedTitle": "翻译错误", + "translate.retry": "重试", + "translate.uploadAnother": "上传其他文件", + "translate.monitor": "AI 监控", + "translate.summary": "摘要", + "translate.cancelProcess": "⟳ 取消流程", + "translate.layoutIntegrity": "布局完整性", + "translate.secureHundred": "100% 安全", + "translate.okHundred": "100% OK", + "translate.preserveLayout": "保留布局", + "translate.preserveLayoutDesc": "保留布局", + "translate.textOnly": "仅文本", + "translate.textOnlyDesc": "仅文本快速翻译", + "translate.unavailableStandard": "标准模式下不可用(仅 AI)" +} diff --git a/frontend/src/lib/i18n/messages/zh/translateComplete.json b/frontend/src/lib/i18n/messages/zh/translateComplete.json new file mode 100644 index 0000000..c3145bb --- /dev/null +++ b/frontend/src/lib/i18n/messages/zh/translateComplete.json @@ -0,0 +1,6 @@ +{ + "translateComplete.highQuality": "高质量", + "translateComplete.segments": "段落", + "translateComplete.characters": "字符", + "translateComplete.confidence": "置信度" +} diff --git a/frontend/src/messages/en.json b/frontend/src/messages/en.json deleted file mode 100644 index 946341f..0000000 --- a/frontend/src/messages/en.json +++ /dev/null @@ -1,394 +0,0 @@ -{ - "common": { - "login": "Login", - "signup": "Sign Up", - "getStarted": "Get Started", - "getStartedFree": "Get Started Free", - "learnMore": "Learn More", - "startNow": "Start Now", - "tryPro": "Try Pro", - "contactSales": "Contact Sales", - "seeDemo": "See Demo", - "free": "Free", - "popular": "Popular", - "month": "month", - "onRequest": "On Request", - "monthly": "Monthly", - "yearly": "Yearly", - "save20": "Save 20%" - }, - "nav": { - "features": "Features", - "pricing": "Pricing", - "enterprise": "Enterprise" - }, - "hero": { - "title": "Translate your Office documents.", - "titleHighlight": "Keep the format.", - "subtitle": "Instantly translate your Excel, Word, and PowerPoint files while preserving their original layout. Secure, accurate, and powered by AI.", - "cta": "Get Started Free", - "demoCta": "See Demo", - "badge1": "Zero data retention", - "badge2": "Deleted in 60 min" - }, - "trustBadges": { - "title": "Trusted by professionals worldwide" - }, - "features": { - "title": "Professional Translation Power", - "subtitle": "Compatible with all your essential office formats, powered by cutting-edge AI for unmatched accuracy.", - "excel": { - "title": "Excel Expert", - "description": "Translate cells and formulas without breaking the spreadsheet. Your data stays intact." - }, - "word": { - "title": "Perfect Word", - "description": "Paragraphs, fonts, and styles preserved identically. Ready to print." - }, - "powerpoint": { - "title": "Intact PowerPoint", - "description": "Slide layout preserved pixel by pixel. Perfect for your presentations." - }, - "ai": { - "title": "Multi-Model AI", - "description": "Choose the engine that fits your content: GPT-4, Claude 3, or Llama 3." - }, - "privacy": { - "title": "Ollama Privacy", - "description": "Local processing option for maximum privacy. Your data never leaves your server." - }, - "speed": { - "title": "Lightning Fast", - "description": "Translate large documents in seconds thanks to our optimized infrastructure." - } - }, - "pricing": { - "title": "Simple and Transparent Pricing", - "subtitle": "Start for free, scale as you need.", - "starter": { - "name": "Starter", - "description": "For individuals and small projects.", - "priceMonthly": "$9", - "priceYearly": "$7.20", - "billedYearly": "Billed $86.40 / year", - "features": [ - "50 documents / month", - "Standard translation (Google/DeepL)", - "Files up to 10 MB", - "Email support" - ] - }, - "pro": { - "name": "Pro", - "description": "For growing professionals.", - "priceMonthly": "$19", - "priceYearly": "$15.20", - "billedYearly": "Billed $182.40 / year", - "features": [ - "200 documents / month", - "Essential AI (DeepSeek V3)", - "Files up to 25 MB", - "Custom glossaries" - ] - }, - "business": { - "name": "Business", - "description": "For large teams.", - "priceMonthly": "$49", - "priceYearly": "$39.20", - "billedYearly": "Billed $470.40 / year", - "features": [ - "1,000 documents / month", - "Premium AI (Claude Haiku)", - "API Access (10K calls)", - "Dedicated support" - ] - } - }, - "cta": { - "title": "Ready to internationalize your documents?", - "subtitle": "Join over 10,000 professionals who save hours of work every week with Office Translator.", - "button": "Start Now" - }, - "footer": { - "privacy": "Privacy", - "terms": "Terms", - "contact": "Contact", - "copyright": "© 2026 Office Translator. All rights reserved." - }, - "cookieConsent": { - "title": "Cookies on Office Translator", - "description": "We use essential cookies so the app works (session, security, language). With your permission, we also use optional cookies to measure traffic and improve the product. Choose “Accept all” to allow optional cookies, or “Essential only” to refuse them.", - "acceptAll": "Accept all", - "essentialOnly": "Essential only", - "learnMore": "Learn more on our site", - "footerHint": "You can clear site data in your browser at any time to see this message again." - }, - "glossaries": { - "title": "Glossaries", - "description": "Manage custom terminology for your LLM translations.", - "createNew": "Create New Glossary", - "yourGlossaries": "Your Glossaries", - "yourGlossariesDesc": "Create and manage glossaries for consistent translations", - "count_one": "{count} glossary", - "count_other": "{count} glossaries", - "defineTerms": "Define term pairs to customize your LLM translations", - "empty": "No glossaries yet", - "emptyDesc": "Create your first glossary to customize translations", - "aboutTitle": "About Glossaries", - "aboutDesc": "Glossaries let you define custom terminology for your translations. When using LLM translation modes, your terms will be applied to ensure consistent translations.", - "aboutFormat": "Format: Each term has a source (original) and target (translation) pair.", - "dialog": { - "title": "New Glossary", - "description": "Import a predefined template, upload a file with your industry jargon, or enter terms manually.", - "nameLabel": "Glossary name", - "namePlaceholder": "e.g. Legal Glossary FR-EN", - "tabTemplates": "Predefined templates", - "tabFile": "Import file", - "tabManual": "Manual entry", - "templatesDesc": "Choose a predefined glossary covering your industry's terminology.", - "templatesEmpty": "No templates available.", - "terms": "terms", - "cancel": "Cancel", - "importing": "Importing…", - "creating": "Creating…", - "importBtn": "Import ({count} terms)", - "createBtn": "Create ({count} terms)", - "createEmpty": "Create glossary", - "selectPrompt": "Select a template", - "dropTitle": "Drop your file here", - "dropOr": "or click to browse", - "dropFormats": "CSV, XLSX, XLS, ODS • max 500 terms", - "parsing": "Parsing file…", - "termsImported": "{count} terms imported", - "changeFile": "Change file", - "retry": "Retry", - "formatTitle": "Expected format:", - "formatDesc": "Two columns with headers:", - "formatNote": "The first row can be a header (source/target) or raw data.", - "errorFormat": "Unsupported format. Use CSV, XLSX, XLS or ODS.", - "errorSize": "File too large (max {max} MB). Split into smaller files.", - "errorEmpty": "No valid terms found. Check that your file has two columns (source, target).", - "errorRead": "Unable to read the file. Check the format." - }, - "toast": { - "created": "Glossary created", - "createdDesc": "\"{name}\" has been created successfully.", - "imported": "Template imported", - "importedDesc": "\"{name}\" has been imported successfully.", - "updated": "Glossary updated", - "updatedDesc": "\"{name}\" has been updated successfully.", - "deleted": "Glossary deleted", - "deletedDesc": "The glossary has been deleted successfully.", - "error": "Error", - "errorCreate": "Failed to create glossary. Please try again.", - "errorImport": "Failed to import template. Please try again.", - "errorUpdate": "Failed to update glossary. Please try again.", - "errorDelete": "Failed to delete glossary. Please try again." - }, - "card": { - "term": "term", - "terms": "terms", - "created": "Created" - }, - "termEditor": { - "sourceTerm": "Source Term", - "targetTranslation": "Target Translation", - "addTerm": "Add Term", - "maxReached": "Maximum {max} terms per glossary reached." - } - }, - "auth": { - "loading": "Loading…", - "or": "or", - "brandName": "Office Translator", - "google": { - "continue": "Continue with Google", - "signUp": "Sign up with Google", - "connecting": "Connecting…", - "errorGeneric": "Something went wrong with Google sign-in.", - "errorFailed": "Google sign-in failed. Please try again.", - "devHint": "To enable Google, add {envKey} in {envFile} (see {exampleFile})." - }, - "login": { - "title": "Welcome back", - "welcomeBack": "Welcome back", - "signInToContinue": "Sign in to keep translating", - "email": "Email", - "password": "Password", - "emailPlaceholder": "you@example.com", - "forgotPassword": "Forgot password?", - "signingIn": "Signing in…", - "signIn": "Sign in", - "errorTitle": "Sign-in error", - "noAccount": "Don't have an account?", - "signUpFree": "Sign up for free", - "orContinueWith": "or continue with email" - }, - "register": { - "title": "Create an account", - "subtitle": "Start translating for free", - "name": "Name", - "namePlaceholder": "Your name", - "email": "Email address", - "emailPlaceholder": "you@example.com", - "password": "Password", - "confirmPassword": "Confirm password", - "createAccount": "Create my account", - "creating": "Creating account…", - "hasAccount": "Already have an account?", - "signIn": "Sign in", - "termsPrefix": "By creating an account, you agree to our", - "termsService": "terms of service", - "registerFailed": "Registration failed", - "errors": { - "nameMin": "Name must be at least 2 characters", - "emailInvalid": "Invalid email address", - "passwordShort": "Password too short (minimum 8 characters)", - "passwordMismatch": "Passwords do not match" - }, - "passwordStrength": { - "label": "Strength", - "weak": "Weak", - "medium": "Medium", - "strong": "Strong" - }, - "toggle": { - "hide": "Hide", - "show": "Show", - "hidePassword": "Hide password", - "showPassword": "Show password" - } - } - }, - "dashboard": { - "nav": { - "overview": "Overview", - "profile": "My profile", - "translate": "Translate", - "apiKeys": "API keys", - "glossaries": "Glossaries" - }, - "header": { - "title": "Dashboard", - "subtitle": "Manage your API and translation settings", - "toggleMenu": "Toggle menu", - "profileTitle": "My profile" - }, - "sidebar": { - "theme": "Theme", - "signOut": "Sign out", - "backHome": "Back to home" - }, - "tier": { - "free": "Free", - "starter": "Starter", - "pro": "Pro", - "business": "Business", - "enterprise": "Enterprise" - }, - "translate": { - "errorNotificationTitle": "Translation error", - "pageTitle": "Translate document", - "pageSubtitle": "Upload an Excel, Word, or PowerPoint file, choose languages and provider, then download your translated file — layout preserved.", - "document": { - "title": "Document", - "descReady": "File ready — you can replace it or continue below.", - "descEmpty": "Drag and drop or browse. We support Office Open XML formats.", - "supportedFormats": "Supported formats: Excel (.xlsx), Word (.docx), PowerPoint (.pptx)" - }, - "settings": { - "title": "Translation settings", - "description": "Languages and engine. LLM options require Pro when applicable.", - "howItWorks": "How it works", - "step1": "Add your file in the panel on the left (or above on small screens).", - "step2": "Pick source and target languages.", - "step3": "Choose a translation provider, then run the job.", - "runHint": "When you are ready, we upload the file and start translation. You can cancel while it runs." - }, - "actions": { - "translate": "Translate document", - "uploading": "Uploading…", - "cancel": "Cancel", - "tryAgain": "Try again", - "statusComplete": "Translation complete", - "statusIssue": "Translation issue", - "statusProgress": "In progress", - "filePrefix": "File:" - }, - "trust": { - "zeroRetention": "Zero data retention", - "deletedAfter": "Files deleted after 60 minutes" - }, - "dropzone": { - "title": "Drag & drop your .xlsx, .docx, or .pptx file here", - "subtitle": "or click to browse", - "uploadAria": "Upload file", - "replaceFile": "Replace file" - }, - "language": { - "loadErrorPrefix": "Failed to load languages:", - "source": "Source language", - "target": "Target language", - "loading": "Loading…", - "autoDetect": "Auto-detect", - "selectPlaceholder": "Select language" - }, - "provider": { - "loading": "Loading providers…", - "noneConfigured": "No providers are configured. Ask your administrator to enable at least one in the admin settings.", - "sectionTitle": "Translation provider", - "llmDivider": "LLM · Context-aware", - "llmDividerPro": "Pro", - "upgrade": "Upgrade to Pro", - "upgradeSuffix": "to use LLM-powered translation.", - "modelTitle": "Model (set by admin):" - }, - "progress": { - "failedTitle": "Translation failed", - "processingFallback": "Processing…", - "connectionLost": "Connection lost. Retrying…", - "timeSeconds": "{seconds}s remaining", - "timeMinutes": "{minutes} min remaining", - "timeMixed": "{minutes}m {seconds}s remaining", - "ariaProgress": "Translation progress" - }, - "complete": { - "title": "Translation complete!", - "descNamed": "“{name}” has been translated successfully.", - "descGeneric": "Your document has been translated successfully.", - "downloading": "Downloading…", - "download": "Download translated file", - "newTranslation": "New translation", - "toastOkTitle": "Download complete", - "toastOkDesc": "{name} has been downloaded successfully.", - "toastFailTitle": "Download failed", - "toastFailDesc": "Could not download the translated file." - }, - "steps": { - "uploading": "Uploading file…", - "starting": "Starting translation…", - "translating": "Translating…" - }, - "errors": { - "jobNotFound": "Translation job not found", - "translationFailed": "Translation failed", - "connectionLost": "Lost connection to the translation service. Check your internet connection and try again." - }, - "translateImages": "Translate images", - "translateImagesDesc": "Extract and translate text inside images (vision required)" - } - }, - "landing": { - "heroDoc": { - "fileName": "Technical_Brief_HVAC.docx", - "ribbonFile": "File", - "ribbonHome": "Home", - "ribbonInsert": "Insert", - "ribbonLayout": "Layout", - "badgeOriginal": "Original (EN)", - "badgeTranslated": "Translation (FR)", - "caption": "One Word document: English on the left, French on the right — same layout preserved." - } - } -} diff --git a/frontend/src/messages/fr.json b/frontend/src/messages/fr.json deleted file mode 100644 index ba17abe..0000000 --- a/frontend/src/messages/fr.json +++ /dev/null @@ -1,394 +0,0 @@ -{ - "common": { - "login": "Connexion", - "signup": "S'inscrire", - "getStarted": "Commencer", - "getStartedFree": "Commencer gratuitement", - "learnMore": "En savoir plus", - "startNow": "Commencer maintenant", - "tryPro": "Essayer Pro", - "contactSales": "Contacter les ventes", - "seeDemo": "Voir la démo", - "free": "Gratuit", - "popular": "Populaire", - "month": "mois", - "onRequest": "Sur devis", - "monthly": "Mensuel", - "yearly": "Annuel", - "save20": "−20 %" - }, - "nav": { - "features": "Fonctionnalités", - "pricing": "Tarifs", - "enterprise": "Entreprise" - }, - "hero": { - "title": "Traduisez vos documents Office.", - "titleHighlight": "Gardez le format.", - "subtitle": "Traduisez instantanément vos fichiers Excel, Word et PowerPoint tout en préservant leur mise en page originale. Sécurisé, précis et propulsé par l'IA.", - "cta": "Commencer gratuitement", - "demoCta": "Voir la démo", - "badge1": "0 données stockées", - "badge2": "Suppression en 60 min" - }, - "trustBadges": { - "title": "Ils nous font confiance" - }, - "features": { - "title": "La puissance de la traduction professionnelle", - "subtitle": "Compatible avec tous vos formats de bureau essentiels, propulsé par une IA de pointe pour une précision inégalée.", - "excel": { - "title": "Expert Excel", - "description": "Traduction des cellules et formules sans casser le tableur. Vos données restent intactes." - }, - "word": { - "title": "Word Parfait", - "description": "Paragraphes, polices et styles conservés à l'identique. Prêt à imprimer." - }, - "powerpoint": { - "title": "PowerPoint Intact", - "description": "Mise en page des diapositives préservée pixel par pixel. Idéal pour vos présentations." - }, - "ai": { - "title": "Multi-Modèles IA", - "description": "Choisissez le moteur qui convient à votre contenu : GPT-4, Claude 3 ou Llama 3." - }, - "privacy": { - "title": "Confidentialité Ollama", - "description": "Option de traitement local pour une confidentialité maximale. Vos données ne quittent pas votre serveur." - }, - "speed": { - "title": "Vitesse Éclair", - "description": "Traduction de documents volumineux en quelques secondes grâce à notre infrastructure optimisée." - } - }, - "pricing": { - "title": "Tarification simple et transparente", - "subtitle": "Commencez gratuitement, évoluez selon vos besoins.", - "starter": { - "name": "Starter", - "description": "Pour les particuliers et petits projets.", - "priceMonthly": "9€", - "priceYearly": "7.20€", - "billedYearly": "Facturé 86.40€ / an", - "features": [ - "50 documents / mois", - "Traductions standards (Google/DeepL)", - "Fichiers jusqu'à 10 Mo", - "Support e-mail" - ] - }, - "pro": { - "name": "Pro", - "description": "Pour les professionnels en croissance.", - "priceMonthly": "19€", - "priceYearly": "15.20€", - "billedYearly": "Facturé 182.40€ / an", - "features": [ - "200 documents / mois", - "IA Essentielle (DeepSeek V3)", - "Fichiers jusqu'à 25 Mo", - "Glossaires personnalisés" - ] - }, - "business": { - "name": "Business", - "description": "Pour les grandes équipes.", - "priceMonthly": "49€", - "priceYearly": "39.20€", - "billedYearly": "Facturé 470.40€ / an", - "features": [ - "1 000 documents / mois", - "IA Premium (Claude Haiku)", - "Accès API (10K appels)", - "Support dédié" - ] - } - }, - "cta": { - "title": "Prêt à internationaliser vos documents ?", - "subtitle": "Rejoignez plus de 10 000 professionnels qui gagnent des heures de travail chaque semaine avec Office Translator.", - "button": "Commencer maintenant" - }, - "footer": { - "privacy": "Confidentialité", - "terms": "CGU", - "contact": "Contact", - "copyright": "© 2026 Office Translator. Tous droits réservés." - }, - "cookieConsent": { - "title": "Cookies sur Office Translator", - "description": "Nous utilisons des cookies strictement nécessaires au fonctionnement du service (session, sécurité, langue). Avec votre accord, nous pouvons aussi utiliser des cookies optionnels pour mesurer l’audience et améliorer le produit. Choisissez « Tout accepter » pour les autoriser, ou « Nécessaires uniquement » pour les refuser.", - "acceptAll": "Tout accepter", - "essentialOnly": "Nécessaires uniquement", - "learnMore": "En savoir plus sur notre site", - "footerHint": "Vous pouvez effacer les données du site dans votre navigateur à tout moment pour revoir ce message." - }, - "glossaries": { - "title": "Glossaires", - "description": "Gérez la terminologie personnalisée pour vos traductions LLM.", - "createNew": "Créer un glossaire", - "yourGlossaries": "Vos glossaires", - "yourGlossariesDesc": "Créez et gérez des glossaires pour des traductions cohérentes", - "count_one": "{count} glossaire", - "count_other": "{count} glossaires", - "defineTerms": "Définissez des paires de termes pour personnaliser vos traductions LLM", - "empty": "Aucun glossaire", - "emptyDesc": "Créez votre premier glossaire pour personnaliser les traductions", - "aboutTitle": "À propos des glossaires", - "aboutDesc": "Les glossaires vous permettent de définir une terminologie personnalisée. En mode traduction LLM, vos termes seront appliqués pour garantir des traductions cohérentes.", - "aboutFormat": "Format : chaque terme possède une source (original) et une cible (traduction).", - "dialog": { - "title": "Nouveau glossaire", - "description": "Importez un template prédéfini, un fichier avec votre jargon métier, ou saisissez vos termes manuellement.", - "nameLabel": "Nom du glossaire", - "namePlaceholder": "ex : Glossaire Juridique FR-EN", - "tabTemplates": "Templates prédéfinis", - "tabFile": "Importer un fichier", - "tabManual": "Saisie manuelle", - "templatesDesc": "Choisissez un glossaire prédéfini couvrant la terminologie de votre domaine.", - "templatesEmpty": "Aucun template disponible.", - "terms": "termes", - "cancel": "Annuler", - "importing": "Importation…", - "creating": "Création…", - "importBtn": "Importer ({count} termes)", - "createBtn": "Créer ({count} termes)", - "createEmpty": "Créer le glossaire", - "selectPrompt": "Sélectionnez un template", - "dropTitle": "Glissez-déposez votre fichier ici", - "dropOr": "ou cliquez pour parcourir", - "dropFormats": "CSV, XLSX, XLS, ODS • max 500 termes", - "parsing": "Analyse du fichier…", - "termsImported": "{count} termes importés", - "changeFile": "Changer de fichier", - "retry": "Réessayer", - "formatTitle": "Format attendu :", - "formatDesc": "Deux colonnes avec en-têtes :", - "formatNote": "La première ligne peut être un en-tête (source/target) ou directement des données.", - "errorFormat": "Format non supporté. Utilisez CSV, XLSX, XLS ou ODS.", - "errorSize": "Fichier trop volumineux (max {max} Mo). Divisez le fichier.", - "errorEmpty": "Aucun terme valide trouvé. Vérifiez les deux colonnes (source, cible).", - "errorRead": "Impossible de lire le fichier. Vérifiez le format." - }, - "toast": { - "created": "Glossaire créé", - "createdDesc": "« {name} » a été créé avec succès.", - "imported": "Template importé", - "importedDesc": "« {name} » a été importé avec succès.", - "updated": "Glossaire mis à jour", - "updatedDesc": "« {name} » a été mis à jour avec succès.", - "deleted": "Glossaire supprimé", - "deletedDesc": "Le glossaire a été supprimé avec succès.", - "error": "Erreur", - "errorCreate": "Impossible de créer le glossaire. Veuillez réessayer.", - "errorImport": "Impossible d'importer le template. Veuillez réessayer.", - "errorUpdate": "Impossible de mettre à jour le glossaire. Veuillez réessayer.", - "errorDelete": "Impossible de supprimer le glossaire. Veuillez réessayer." - }, - "card": { - "term": "terme", - "terms": "termes", - "created": "Créé le" - }, - "termEditor": { - "sourceTerm": "Terme source", - "targetTranslation": "Traduction cible", - "addTerm": "Ajouter un terme", - "maxReached": "Maximum {max} termes par glossaire atteint." - } - }, - "auth": { - "loading": "Chargement…", - "or": "ou", - "brandName": "Office Translator", - "google": { - "continue": "Continuer avec Google", - "signUp": "S'inscrire avec Google", - "connecting": "Connexion…", - "errorGeneric": "Erreur lors de la connexion Google.", - "errorFailed": "La connexion Google a échoué. Veuillez réessayer.", - "devHint": "Pour activer Google : ajoutez {envKey} dans {envFile} (voir {exampleFile})." - }, - "login": { - "title": "Bon retour", - "welcomeBack": "Bon retour", - "signInToContinue": "Connectez-vous pour continuer à traduire", - "email": "E-mail", - "password": "Mot de passe", - "emailPlaceholder": "vous@exemple.com", - "forgotPassword": "Mot de passe oublié ?", - "signingIn": "Connexion…", - "signIn": "Se connecter", - "errorTitle": "Erreur de connexion", - "noAccount": "Pas encore de compte ?", - "signUpFree": "Créer un compte gratuitement", - "orContinueWith": "ou continuer avec email" - }, - "register": { - "title": "Créer un compte", - "subtitle": "Commencez à traduire gratuitement", - "name": "Nom", - "namePlaceholder": "Votre nom", - "email": "Adresse e-mail", - "emailPlaceholder": "vous@exemple.com", - "password": "Mot de passe", - "confirmPassword": "Confirmer le mot de passe", - "createAccount": "Créer mon compte", - "creating": "Création du compte…", - "hasAccount": "Vous avez déjà un compte ?", - "signIn": "Se connecter", - "termsPrefix": "En créant un compte, vous acceptez notre", - "termsService": "conditions d'utilisation du service", - "registerFailed": "L'inscription a échoué", - "errors": { - "nameMin": "Le nom doit contenir au moins 2 caractères", - "emailInvalid": "Adresse e-mail invalide", - "passwordShort": "Mot de passe trop court (minimum 8 caractères)", - "passwordMismatch": "Les mots de passe ne correspondent pas" - }, - "passwordStrength": { - "label": "Force", - "weak": "Faible", - "medium": "Moyen", - "strong": "Fort" - }, - "toggle": { - "hide": "Masquer", - "show": "Afficher", - "hidePassword": "Masquer le mot de passe", - "showPassword": "Afficher le mot de passe" - } - } - }, - "dashboard": { - "nav": { - "overview": "Vue d’ensemble", - "profile": "Mon profil", - "translate": "Traduire", - "apiKeys": "Clés API", - "glossaries": "Glossaires" - }, - "header": { - "title": "Tableau de bord", - "subtitle": "Gérez votre API et vos paramètres de traduction", - "toggleMenu": "Ouvrir le menu", - "profileTitle": "Mon profil" - }, - "sidebar": { - "theme": "Thème", - "signOut": "Déconnexion", - "backHome": "Retour à l’accueil" - }, - "tier": { - "free": "Gratuit", - "starter": "Starter", - "pro": "Pro", - "business": "Business", - "enterprise": "Entreprise" - }, - "translate": { - "errorNotificationTitle": "Erreur de traduction", - "pageTitle": "Traduire un document", - "pageSubtitle": "Importez un fichier Excel, Word ou PowerPoint, choisissez les langues et le moteur, puis téléchargez le document traduit — mise en page conservée.", - "document": { - "title": "Document", - "descReady": "Fichier prêt — vous pouvez le remplacer ou continuer ci-dessous.", - "descEmpty": "Glissez-déposez ou parcourez vos fichiers. Formats Office Open XML pris en charge.", - "supportedFormats": "Formats pris en charge : Excel (.xlsx), Word (.docx), PowerPoint (.pptx)" - }, - "settings": { - "title": "Paramètres de traduction", - "description": "Langues et moteur. Les options LLM nécessitent Pro le cas échéant.", - "howItWorks": "Comment ça marche", - "step1": "Ajoutez votre fichier dans le panneau de gauche (ou au-dessus sur petit écran).", - "step2": "Choisissez la langue source et la langue cible.", - "step3": "Sélectionnez un fournisseur de traduction, puis lancez la tâche.", - "runHint": "Quand vous êtes prêt, nous envoyons le fichier et démarrons la traduction. Vous pouvez annuler pendant l’exécution." - }, - "actions": { - "translate": "Traduire le document", - "uploading": "Envoi en cours…", - "cancel": "Annuler", - "tryAgain": "Réessayer", - "statusComplete": "Traduction terminée", - "statusIssue": "Problème de traduction", - "statusProgress": "En cours", - "filePrefix": "Fichier :" - }, - "trust": { - "zeroRetention": "Aucune conservation des données", - "deletedAfter": "Fichiers supprimés après 60 minutes" - }, - "dropzone": { - "title": "Glissez-déposez votre fichier .xlsx, .docx ou .pptx ici", - "subtitle": "ou cliquez pour choisir un fichier", - "uploadAria": "Téléverser un fichier", - "replaceFile": "Remplacer le fichier" - }, - "language": { - "loadErrorPrefix": "Impossible de charger les langues :", - "source": "Langue source", - "target": "Langue cible", - "loading": "Chargement…", - "autoDetect": "Détection automatique", - "selectPlaceholder": "Choisir une langue" - }, - "provider": { - "loading": "Chargement des fournisseurs…", - "noneConfigured": "Aucun fournisseur n’est configuré. Demandez à un administrateur d’en activer au moins un dans les réglages admin.", - "sectionTitle": "Fournisseur de traduction", - "llmDivider": "LLM · Contextuel", - "llmDividerPro": "Pro", - "upgrade": "Passer à Pro", - "upgradeSuffix": "pour utiliser la traduction par LLM.", - "modelTitle": "Modèle (défini par l’admin) :" - }, - "progress": { - "failedTitle": "Échec de la traduction", - "processingFallback": "Traitement…", - "connectionLost": "Connexion perdue. Nouvelle tentative…", - "timeSeconds": "{seconds} s restantes", - "timeMinutes": "{minutes} min restantes", - "timeMixed": "{minutes} min {seconds} s restantes", - "ariaProgress": "Progression de la traduction" - }, - "complete": { - "title": "Traduction terminée !", - "descNamed": "« {name} » a été traduit avec succès.", - "descGeneric": "Votre document a été traduit avec succès.", - "downloading": "Téléchargement…", - "download": "Télécharger le fichier traduit", - "newTranslation": "Nouvelle traduction", - "toastOkTitle": "Téléchargement terminé", - "toastOkDesc": "{name} a été téléchargé avec succès.", - "toastFailTitle": "Échec du téléchargement", - "toastFailDesc": "Impossible de télécharger le fichier traduit." - }, - "steps": { - "uploading": "Envoi du fichier…", - "starting": "Démarrage de la traduction…", - "translating": "Traduction en cours…" - }, - "errors": { - "jobNotFound": "Tâche de traduction introuvable", - "translationFailed": "La traduction a échoué", - "connectionLost": "Connexion au service de traduction perdue. Vérifiez votre connexion internet et réessayez." - }, - "translateImages": "Traduire les images", - "translateImagesDesc": "Extraire et traduire le texte des images (vision requise)" - } - }, - "landing": { - "heroDoc": { - "fileName": "Note_technique_CVC.docx", - "ribbonFile": "Fichier", - "ribbonHome": "Accueil", - "ribbonInsert": "Insertion", - "ribbonLayout": "Mise en page", - "badgeOriginal": "Original (EN)", - "badgeTranslated": "Traduction (FR)", - "caption": "Un seul fichier Word : l’anglais à gauche, le français à droite — la mise en forme reste identique." - } - } -} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index b0ca7bf..af12c36 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ dependencies = [ "deep-translator==1.11.4", "fastapi==0.109.0", "greenlet>=3.0.0", - "httpx>=0.27.0", + "httpx>=0.27.0,<0.28", "ipykernel==6.27.1", "lxml>=4.9.0", "matplotlib==3.8.2", @@ -46,3 +46,21 @@ dependencies = [ "structlog>=24.1.0", "uvicorn[standard]==0.27.0", ] + +[dependency-groups] +dev = [ + "ruff>=0.6.0", + "pytest-cov>=5.0.0", +] + +[tool.ruff] +line-length = 100 +target-version = "py312" + +[tool.ruff.lint] +select = ["E", "F", "I", "W", "UP", "B", "C4", "SIM"] +ignore = ["E501"] + +[tool.ruff.lint.pydocstyle] +convention = "google" + diff --git a/pytest.ini b/pytest.ini index 2f4c80e..57bfa13 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,2 +1,4 @@ [pytest] asyncio_mode = auto +testpaths = tests +addopts = --cov=routes --cov=services --cov=translators --cov=middleware --cov=utils --cov=models --cov-report=term-missing diff --git a/routes/legacy_routes.py b/routes/legacy_routes.py index cfbd5ea..2161307 100644 --- a/routes/legacy_routes.py +++ b/routes/legacy_routes.py @@ -21,26 +21,6 @@ logger = logging.getLogger(__name__) router = APIRouter(prefix="/api/v1", tags=["Legacy"]) -def _safe_output_path(filename: str): - """ - Resolve filename to a path under config.OUTPUT_DIR. Prevents path traversal. - Returns (Path, True) if valid, (None, False) if invalid. - """ - if not filename or ".." in filename or "/" in filename or "\\" in filename: - return None, False - safe_name = Path(filename).name - if not safe_name.strip(): - return None, False - base = config.OUTPUT_DIR.resolve() - try: - resolved = (config.OUTPUT_DIR / safe_name).resolve() - if not resolved.is_relative_to(base): - return None, False - return resolved, True - except (ValueError, OSError): - return None, False - - def _resolve_model( cfg_model: Optional[str], model_env: str, @@ -340,41 +320,6 @@ async def translate_batch_documents( } -@router.get("/download/{filename}") -async def download_file(filename: str): - """Download a translated file by filename. Filename is sanitized to prevent path traversal.""" - file_path, ok = _safe_output_path(filename) - if not ok or file_path is None: - raise HTTPException(status_code=400, detail="Invalid filename") - if not file_path.exists(): - raise HTTPException(status_code=404, detail="File not found") - return FileResponse( - path=file_path, - filename=file_path.name, - media_type="application/octet-stream", - ) - - -@router.delete("/cleanup/{filename}") -async def cleanup_translated_file(filename: str): - """Cleanup a translated file after download. Filename is sanitized to prevent path traversal.""" - file_path, ok = _safe_output_path(filename) - if not ok or file_path is None: - raise HTTPException(status_code=400, detail="Invalid filename") - try: - if not file_path.exists(): - raise HTTPException(status_code=404, detail="File not found") - file_handler.cleanup_file(file_path) - return {"message": f"File {file_path.name} deleted successfully"} - except HTTPException: - raise - except Exception as e: - logger.exception("Cleanup error") - raise HTTPException( - status_code=500, detail="Erreur lors de la suppression du fichier." - ) - - @router.post("/extract-texts") async def extract_texts_from_document( file: UploadFile = File(..., description="Document file to extract texts from"), diff --git a/scripts/analyze_i18n.py b/scripts/analyze_i18n.py new file mode 100644 index 0000000..fdce74a --- /dev/null +++ b/scripts/analyze_i18n.py @@ -0,0 +1,20 @@ +import re +from pathlib import Path +from collections import Counter + +content = Path("frontend/src/lib/i18n.tsx").read_text(encoding="utf-8") + +# Extract the en block (from "en: {" up to "\n },\n fr:") +m = re.search(r'en:\s*\{(.*?)\n\s*\},\s*\n\s*fr:', content, re.DOTALL) +if not m: + print("Could not find en block") + raise SystemExit(1) + +en_block = m.group(1) +# Find all top-level keys in the en dictionary +keys = re.findall(r'"([a-zA-Z0-9_\-\.]+)":', en_block) +namespaces = Counter(k.split('.')[0] for k in keys) + +for ns, count in namespaces.most_common(): + print(f"{ns}: {count}") +print(f"Total keys: {len(keys)}") diff --git a/scripts/generate_i18n_index.py b/scripts/generate_i18n_index.py new file mode 100644 index 0000000..7a50330 --- /dev/null +++ b/scripts/generate_i18n_index.py @@ -0,0 +1,39 @@ +""" +Generate per-locale index.ts files that merge all namespace JSON files. + +Creates: + frontend/src/lib/i18n/messages//index.ts +""" + +import json +from pathlib import Path +from collections import defaultdict + +ROOT = Path(__file__).parent.parent +MESSAGES_DIR = ROOT / "frontend" / "src" / "lib" / "i18n" / "messages" + +manifest = json.loads((MESSAGES_DIR / "index.json").read_text(encoding="utf-8")) + +for locale in manifest["locales"]: + locale_dir = MESSAGES_DIR / locale + namespaces = sorted(p.stem for p in locale_dir.glob("*.json")) + + imports = "\n".join(f'import {ns} from "./{ns}.json";' + for ns in namespaces) + export_obj = "\n ".join(f"...{ns}," for ns in namespaces) + + index_ts = f'''// Auto-generated by scripts/generate_i18n_index.py +// Merges all namespace JSON files for locale "{locale}". + +{imports} + +const messages: Record = {{ + {export_obj} +}}; + +export default messages; +''' + + (locale_dir / "index.ts").write_text(index_ts, encoding="utf-8") + +print(f"Generated index.ts for {len(manifest['locales'])} locales") diff --git a/scripts/split_i18n.py b/scripts/split_i18n.py new file mode 100644 index 0000000..874b877 --- /dev/null +++ b/scripts/split_i18n.py @@ -0,0 +1,107 @@ +""" +Split frontend/src/lib/i18n.tsx into per-locale, per-namespace JSON files. + +Generates: + frontend/src/lib/i18n/messages//.json + frontend/src/lib/i18n/messages/index.json (manifest) +""" + +import json +import re +from pathlib import Path +from collections import defaultdict + +ROOT = Path(__file__).parent.parent +SOURCE = ROOT / "frontend" / "src" / "lib" / "i18n.tsx" +OUT_DIR = ROOT / "frontend" / "src" / "lib" / "i18n" / "messages" + +content = SOURCE.read_text(encoding="utf-8") + +def find_locale_blocks(text: str) -> list[tuple[str, str]]: + """Find each locale block using brace matching.""" + blocks = [] + pattern = re.compile(r'\n\s*([a-z]{2}):\s*\{') + for match in pattern.finditer(text): + locale = match.group(1) + start = match.end() - 1 # position of the opening '{' + brace_count = 0 + in_string = False + escape = False + i = start + while i < len(text): + ch = text[i] + if escape: + escape = False + elif ch == "\\": + escape = True + elif ch == '"': + in_string = not in_string + elif not in_string: + if ch == "{": + brace_count += 1 + elif ch == "}": + brace_count -= 1 + if brace_count == 0: + blocks.append((locale, text[start + 1 : i])) + break + i += 1 + return blocks + +def parse_block(block: str) -> dict[str, str]: + """Parse key: value pairs from a locale block. Values may be concatenated strings.""" + messages = {} + # Match "key": value, where value is a string literal possibly followed by + "..." + entry_pattern = re.compile( + r'"([a-zA-Z0-9_\-\.]+)":\s*((?:"(?:[^"\\]|\\.)*"\s*(?:\+\s*)?)+)', + re.DOTALL, + ) + for match in entry_pattern.finditer(block): + key = match.group(1) + raw = match.group(2) + parts = re.findall(r'"((?:[^"\\]|\\.)*)"', raw) + value = "".join(parts) + messages[key] = value + return messages + +OUT_DIR.mkdir(parents=True, exist_ok=True) + +manifest: dict[str, list[str]] = defaultdict(list) +all_namespaces: set[str] = set() + +for locale, block in find_locale_blocks(content): + messages = parse_block(block) + by_namespace: dict[str, dict[str, str]] = defaultdict(dict) + for key, value in messages.items(): + namespace = key.split(".")[0] + by_namespace[namespace][key] = value + all_namespaces.add(namespace) + + locale_dir = OUT_DIR / locale + locale_dir.mkdir(parents=True, exist_ok=True) + for namespace, msgs in by_namespace.items(): + (locale_dir / f"{namespace}.json").write_text( + json.dumps(msgs, indent=2, ensure_ascii=False) + "\n", + encoding="utf-8", + ) + if namespace not in manifest[locale]: + manifest[locale].append(namespace) + +# Write manifest +manifest = {loc: sorted(manifest[loc]) for loc in sorted(manifest)} +(OUT_DIR / "index.json").write_text( + json.dumps( + { + "locales": list(manifest.keys()), + "namespaces": sorted(all_namespaces), + "manifest": manifest, + }, + indent=2, + ensure_ascii=False, + ) + + "\n", + encoding="utf-8", +) + +print(f"Wrote namespace files for {len(manifest)} locales") +print(f"Namespaces: {len(all_namespaces)}") +print(f"Total keys (en): {sum(len(manifest[loc]) for loc in manifest)}") diff --git a/services/translation_service.py b/services/translation_service.py index 6fa19c2..d861ab6 100644 --- a/services/translation_service.py +++ b/services/translation_service.py @@ -1207,28 +1207,55 @@ class TranslationService: """ Translate multiple text strings efficiently using batch processing. + Deduplicates non-empty texts before sending them to the provider so that + repeated strings (common in documents with headers, formulas, tables) + are translated only once. This reduces API calls, cost and latency. + Args: texts: List of texts to translate target_language: Target language code source_language: Source language code (default: 'auto') Returns: - List of translated texts + List of translated texts in the same order as input """ if not texts: return [] - # Use provider's batch method if available - if hasattr(self.provider, "translate_batch"): - return self.provider.translate_batch( - texts, target_language, source_language - ) + # Preserve original positions and filter out empty/whitespace-only texts + results: list[str] = [""] * len(texts) + unique_texts: list[str] = [] + text_to_positions: dict[str, list[int]] = {} - # Fallback to individual translations - return [ - self.translate_text(text, target_language, source_language) - for text in texts - ] + for idx, text in enumerate(texts): + if not text or not text.strip(): + results[idx] = text if text else "" + continue + if text not in text_to_positions: + text_to_positions[text] = [] + unique_texts.append(text) + text_to_positions[text].append(idx) + + if not unique_texts: + return results + + # Translate unique texts only + if hasattr(self.provider, "translate_batch"): + translated_unique = self.provider.translate_batch( + unique_texts, target_language, source_language + ) + else: + translated_unique = [ + self.translate_text(text, target_language, source_language) + for text in unique_texts + ] + + # Map translated texts back to their original positions + for original, translated in zip(unique_texts, translated_unique): + for idx in text_to_positions[original]: + results[idx] = translated if translated else original + + return results # Global translation service instance diff --git a/tests/test_story_3_5_api_versioning.py b/tests/test_story_3_5_api_versioning.py index 5db3b2f..56a65f1 100644 --- a/tests/test_story_3_5_api_versioning.py +++ b/tests/test_story_3_5_api_versioning.py @@ -257,12 +257,12 @@ class TestMigratedEndpoints: assert response.status_code in [400, 422, 429] def test_download_endpoint_versioned(self, client): - """AC1: Download endpoint should be accessible under /api/v1/download/{filename}""" + """Legacy filename-based download endpoint was removed for security.""" response = client.get("/api/v1/download/testfile.xlsx") assert response.status_code in [404, 429] def test_cleanup_endpoint_versioned(self, client): - """AC1: Cleanup endpoint should be accessible under /api/v1/cleanup/{filename}""" + """Legacy filename-based cleanup endpoint was removed for security.""" response = client.delete("/api/v1/cleanup/testfile.xlsx") assert response.status_code in [404, 429] diff --git a/tests/test_translation_service.py b/tests/test_translation_service.py new file mode 100644 index 0000000..decd221 --- /dev/null +++ b/tests/test_translation_service.py @@ -0,0 +1,40 @@ +"""Tests for services/translation_service.py.""" + +import pytest +from services.translation_service import TranslationService, TranslationProvider + + +class DummyProvider(TranslationProvider): + """Provider that records every unique text it is asked to translate.""" + + def __init__(self): + self.calls: list[str] = [] + + def translate(self, text: str, target_language: str, source_language: str = "auto") -> str: + self.calls.append(text) + return f"[{text}]" + + +class TestTranslateBatchDeduplication: + def test_duplicate_texts_translated_once(self): + provider = DummyProvider() + service = TranslationService(provider=provider) + + texts = ["hello", "world", "hello", "planet", "world", ""] + results = service.translate_batch(texts, "fr", "en") + + assert results == ["[hello]", "[world]", "[hello]", "[planet]", "[world]", ""] + # Only 3 unique non-empty texts should be sent to the provider + assert sorted(provider.calls) == sorted(["hello", "world", "planet"]) + + def test_empty_and_whitespace_preserved(self): + provider = DummyProvider() + service = TranslationService(provider=provider) + + texts = ["", " ", "ok"] + results = service.translate_batch(texts, "fr", "en") + + assert results[0] == "" + assert results[1] == " " + assert results[2] == "[ok]" + assert provider.calls == ["ok"]