perf+security: fix build, secure downloads, dedupe translations, refactor i18n
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m49s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m49s
Frontend:
- Fix Framer Motion / motion-dom build error by pinning framer-motion to
11.18.2 (compatible with React 19 and Next.js 16).
- Add cross-env and build:local script to bypass standalone symlink errors
on Windows without Developer Mode.
- Allow NEXT_OUTPUT=default to disable standalone output for local builds.
- Refactor i18n: split 14,177-line src/lib/i18n.tsx into per-locale,
per-namespace JSON files under src/lib/i18n/messages/.
- Load English synchronously; other locales loaded on demand via dynamic
imports (reduces initial bundle, improves maintainability).
- Remove unused next-intl message files src/messages/en.json and fr.json.
Backend:
- Remove insecure legacy /api/v1/download/{filename} and /api/v1/cleanup/{filename}
endpoints. The job-based /api/v1/download/{job_id} already enforces ownership.
- Deduplicate texts in TranslationService.translate_batch before sending them
to the provider, reducing API calls for repeated strings.
- Pin httpx to <0.28 to fix TestClient incompatibility with starlette 0.35.1.
- Add pytest-cov and ruff dev dependencies/config.
DevOps:
- Remove hardcoded Grafana password from docker-compose.yml and
docker-compose.monitoring.yml; use GRAFANA_PASSWORD env var.
- Change default TRANSLATION_SERVICE from ollama to google in
docker-compose.yml (Ollama is an optional profile).
- Add GRAFANA_PASSWORD to .env.example.
- Add .coverage and frontend/pnpm-workspace.yaml to .gitignore.
Tests:
- Update API versioning tests for removed legacy endpoints.
- Add tests/test_translation_service.py for deduplication behavior.
Verified:
- pnpm run build:local passes.
- uv run pytest tests/test_providers/* tests/test_translation_service.py
tests/test_story_3_5_api_versioning.py tests/test_download_endpoint.py
tests/test_translators/test_excel_translator.py: provider/translator tests
pass; one pre-existing French error-message test still fails (message is
returned in English, unrelated to this change).
This commit is contained in:
92
frontend/src/lib/i18n/messages/ar/translate.json
Normal file
92
frontend/src/lib/i18n/messages/ar/translate.json
Normal file
@@ -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 فقط)"
|
||||
}
|
||||
Reference in New Issue
Block a user