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:
151
frontend/src/lib/i18n/messages/pt/pricing.json
Normal file
151
frontend/src/lib/i18n/messages/pt/pricing.json
Normal file
@@ -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": "✕"
|
||||
}
|
||||
Reference in New Issue
Block a user