Files
scripts/translate-wp-plugin/setup_glossary.py

348 lines
10 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
setup_glossary.py — Cria/actualiza glossário DeepL para WordPress PT-PT.
Combina:
1. Brand names dos plugins (mantidos sem tradução)
2. Termos WordPress PT-PT preferidos (Settings → Definições, etc.)
3. Plataformas sociais que DeepL traduz incorrectamente (Discord → Discórdia)
Uso:
python3 setup_glossary.py # cria/actualiza e guarda ID em .env
python3 setup_glossary.py --list # lista glossários existentes
python3 setup_glossary.py --test # testa tradução com glossário
Author: Descomplicar®
Version: 1.0.0
"""
import sys
import os
from pathlib import Path
# Carregar .env
_env_file = Path(__file__).parent / '.env'
if _env_file.exists():
for _line in _env_file.read_text().splitlines():
if '=' in _line and not _line.startswith('#'):
_k, _v = _line.split('=', 1)
os.environ.setdefault(_k.strip(), _v.strip())
try:
import deepl
except ImportError:
print("ERRO: pip3 install deepl", file=sys.stderr)
sys.exit(1)
DEEPL_AUTH_KEY = os.environ.get('DEEPL_API_KEY', '')
GLOSSARY_NAME = 'WordPress PT-PT'
# ---------------------------------------------------------------------------
# 1. BRAND NAMES — manter exactamente como em inglês
# ---------------------------------------------------------------------------
BRAND_NAMES = {
# Plugins desta biblioteca
'AI Engine': 'AI Engine',
'Astra': 'Astra',
'BDThemes Element Pack': 'BDThemes Element Pack',
'BetterDocs': 'BetterDocs',
'Bit Integrations': 'Bit Integrations',
'Bit Social': 'Bit Social',
'Branda': 'Branda',
'Docket Cache': 'Docket Cache',
'Elementor': 'Elementor',
'Elementor Pro': 'Elementor Pro',
'ElementsKit': 'ElementsKit',
'Email Candy': 'Email Candy',
'Envato Elements': 'Envato Elements',
'Eventin': 'Eventin',
'FileBird': 'FileBird',
'Fluent Booking': 'Fluent Booking',
'FluentCRM': 'FluentCRM',
'FluentForms': 'FluentForms',
'Fluent Forms': 'Fluent Forms',
'Fluent SMTP': 'Fluent SMTP',
'Fluent Support': 'Fluent Support',
'Forminator': 'Forminator',
'GUM Elementor Addon': 'GUM Elementor Addon',
'Happy Elementor Addons': 'Happy Elementor Addons',
'HappyFiles': 'HappyFiles',
'Insert Headers and Footers': 'Insert Headers and Footers',
'JetEngine': 'JetEngine',
'KiviCare': 'KiviCare',
'Loco Translate': 'Loco Translate',
'LoginPress': 'LoginPress',
'MainWP': 'MainWP',
'BackWPup': 'BackWPup',
'MetForm': 'MetForm',
'PowerPack Elements': 'PowerPack Elements',
'Rank Math': 'Rank Math',
'Real Cookie Banner': 'Real Cookie Banner',
'Shipper': 'Shipper',
'TablePress': 'TablePress',
'Ultimate Branding': 'Ultimate Branding',
'Uncanny Automator': 'Uncanny Automator',
'UpdraftPlus': 'UpdraftPlus',
'WebP Express': 'WebP Express',
'WholesaleX': 'WholesaleX',
'WooCommerce': 'WooCommerce',
'WooCommerce Dashboard Stats': 'WooCommerce Dashboard Stats',
'Wordfence': 'Wordfence',
'WPCode': 'WPCode',
'WP Defender': 'WP Defender',
'WPForms': 'WPForms',
'WPFunnels': 'WPFunnels',
'WP Hummingbird': 'WP Hummingbird',
'WP Mail SMTP': 'WP Mail SMTP',
'WP Rocket': 'WP Rocket',
'WP Smush': 'WP Smush',
'WP Security Audit Log': 'WP Security Audit Log',
'WPMU DEV': 'WPMU DEV',
'WP-Optimize': 'WP-Optimize',
'WP Fastest Cache': 'WP Fastest Cache',
# Core WordPress
'WordPress': 'WordPress',
'Gutenberg': 'Gutenberg',
'WP-CLI': 'WP-CLI',
'phpMyAdmin': 'phpMyAdmin',
# Plugins adicionais starter.descomplicar.pt
'Complianz': 'Complianz',
'WP Activity Log': 'WP Activity Log',
'Meow Apps': 'Meow Apps',
'Happy Addons': 'Happy Addons',
# Termos AI/LLM que DeepL traduz incorrectamente
'Playground': 'Playground',
'Chatbot': 'Chatbot',
'Prompt': 'Prompt',
'Prompts': 'Prompts',
'Token': 'Token',
'Tokens': 'Tokens',
'Embedding': 'Embedding',
'Embeddings': 'Embeddings',
'Fine-tuning': 'Ajuste fino',
'Finetune': 'Ajuste fino',
'MCP': 'MCP',
# Plataformas que DeepL traduz (Discord → Discórdia, etc.)
'Discord': 'Discord',
'Slack': 'Slack',
'GitHub': 'GitHub',
'GitLab': 'GitLab',
'Bitbucket': 'Bitbucket',
'Zapier': 'Zapier',
'HubSpot': 'HubSpot',
'Mailchimp': 'Mailchimp',
'SendGrid': 'SendGrid',
'Twilio': 'Twilio',
'Stripe': 'Stripe',
'PayPal': 'PayPal',
'Moloni': 'Moloni',
'Multibanco': 'Multibanco',
'Google Analytics': 'Google Analytics',
'Google Tag Manager': 'Google Tag Manager',
'Google Search Console': 'Google Search Console',
'Google reCAPTCHA': 'Google reCAPTCHA',
'Facebook Pixel': 'Facebook Pixel',
'WhatsApp': 'WhatsApp',
'Telegram': 'Telegram',
'TikTok': 'TikTok',
'LinkedIn': 'LinkedIn',
'YouTube': 'YouTube',
'Instagram': 'Instagram',
'Twitter': 'Twitter',
'Twitch': 'Twitch',
'Pinterest': 'Pinterest',
'Dropbox': 'Dropbox',
'Amazon S3': 'Amazon S3',
'Google Drive': 'Google Drive',
'OneDrive': 'OneDrive',
# Termos técnicos a manter em inglês
'API': 'API',
'JSON': 'JSON',
'REST API': 'REST API',
'CSS': 'CSS',
'HTML': 'HTML',
'PHP': 'PHP',
'JavaScript': 'JavaScript',
'URL': 'URL',
'SSL': 'SSL',
'HTTPS': 'HTTPS',
'CDN': 'CDN',
'DNS': 'DNS',
'SMTP': 'SMTP',
'IMAP': 'IMAP',
'FTP': 'SFTP',
'SFTP': 'SFTP',
'OAuth': 'OAuth',
'JWT': 'JWT',
'SEO': 'SEO',
'UI': 'UI',
'UX': 'UX',
'CRM': 'CRM',
'SaaS': 'SaaS',
'GDPR': 'RGPD',
}
# ---------------------------------------------------------------------------
# 2. TERMOS WORDPRESS PT-PT
# Apenas termos críticos onde DeepL pode usar PT-BR
# ---------------------------------------------------------------------------
WORDPRESS_TERMS = {
'Settings': 'Definições',
'Password': 'Palavra-passe',
'Dashboard': 'Painel de controlo',
'Update': 'Actualização',
'Updates': 'Actualizações',
'Backup': 'Cópia de segurança',
'Backups': 'Cópias de segurança',
'Plugin': 'Plugin',
'Plugins': 'Plugins',
'Widget': 'Widget',
'Widgets': 'Widgets',
'Theme': 'Tema',
'Themes': 'Temas',
'Shortcode': 'Código curto',
'Webhook': 'Webhook',
'Log': 'Registo',
'Logs': 'Registos',
'Cache': 'Cache',
'Firewall': 'Firewall',
'Malware': 'Malware',
# E-commerce
'Cart': 'Carrinho',
'Checkout': 'Finalização de compra',
'Order': 'Encomenda',
'Orders': 'Encomendas',
'Coupon': 'Cupão',
'Coupons': 'Cupões',
'Stock': 'Stock',
'Inventory': 'Inventário',
'SKU': 'Referência',
'VAT': 'IVA',
# Segurança
'Login': 'Início de sessão',
'Logout': 'Terminar sessão',
'Whitelist': 'Lista de permissões',
'Blacklist': 'Lista de bloqueios',
# Formulários
'Checkbox': 'Caixa de seleção',
'Dropdown': 'Lista pendente',
'Submit': 'Submeter',
# Acções comuns
'Save': 'Guardar',
'Delete': 'Eliminar',
'Reset': 'Repor',
'Upload': 'Carregar',
'Download': 'Transferir',
}
# ---------------------------------------------------------------------------
def get_all_entries() -> dict:
entries = {}
entries.update(BRAND_NAMES)
entries.update(WORDPRESS_TERMS)
return entries
def list_glossaries(translator):
glossaries = translator.list_glossaries()
if not glossaries:
print("Sem glossários criados.")
return
for g in glossaries:
print(f" {g.name!r} — ID: {g.glossary_id} | {g.entry_count} entradas | {g.source_lang}{g.target_lang}")
def create_or_update_glossary(translator) -> str:
entries = get_all_entries()
print(f" Entradas a carregar: {len(entries)}")
# Verificar se já existe glossário com este nome e apagar
existing = translator.list_glossaries()
for g in existing:
if g.name == GLOSSARY_NAME:
print(f" Glossário existente encontrado (ID: {g.glossary_id}) — a substituir...")
translator.delete_glossary(g.glossary_id)
break
glossary = translator.create_glossary(
GLOSSARY_NAME,
source_lang='EN',
target_lang='PT',
entries=entries,
)
print(f" Glossário criado: {glossary.glossary_id}")
print(f" Entradas confirmadas: {glossary.entry_count}")
return glossary.glossary_id
def save_glossary_id(glossary_id: str):
env_path = Path(__file__).parent / '.env'
content = env_path.read_text()
if 'DEEPL_GLOSSARY_ID=' in content:
lines = []
for line in content.splitlines():
if line.startswith('DEEPL_GLOSSARY_ID='):
lines.append(f'DEEPL_GLOSSARY_ID={glossary_id}')
else:
lines.append(line)
env_path.write_text('\n'.join(lines) + '\n')
else:
with open(env_path, 'a') as f:
f.write(f'\nDEEPL_GLOSSARY_ID={glossary_id}\n')
print(f" ID guardado em .env: DEEPL_GLOSSARY_ID={glossary_id}")
def test_glossary(translator, glossary_id: str):
test_strings = [
'Discord notifications',
'Go to Settings',
'UpdraftPlus Backup',
'Password reset',
'WooCommerce Cart',
'Wordfence Firewall',
'Update available',
]
print(f"\n Teste de tradução com glossário:")
results = translator.translate_text(
test_strings,
source_lang='EN',
target_lang='PT-PT',
glossary=glossary_id,
)
for src, res in zip(test_strings, results):
print(f" EN: {src!r}")
print(f" PT: {res.text!r}")
print()
def main():
if not DEEPL_AUTH_KEY:
print("ERRO: DEEPL_API_KEY não definida.", file=sys.stderr)
sys.exit(1)
args = sys.argv[1:]
translator = deepl.Translator(DEEPL_AUTH_KEY)
if '--list' in args:
print("\nGlossários DeepL:")
list_glossaries(translator)
return
print(f"\n{'='*60}")
print(f" Setup Glossário DeepL — {GLOSSARY_NAME}")
print(f"{'='*60}")
glossary_id = create_or_update_glossary(translator)
save_glossary_id(glossary_id)
if '--test' in args or True: # sempre testar
test_glossary(translator, glossary_id)
print(f"\n Concluído. Usar DEEPL_GLOSSARY_ID={glossary_id}")
if __name__ == '__main__':
main()