#!/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()