init: scripts diversos (crawlers, conversores, scrapers)

This commit is contained in:
2026-03-05 20:38:36 +00:00
commit 6ac6f4be2a
925 changed files with 850330 additions and 0 deletions

348
translate-wp-plugin/fix_ptbr.py Executable file
View File

@@ -0,0 +1,348 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
fix_ptbr.py — Corrige termos PT-BR para PT-PT em ficheiros .po.
Aplica substituições apenas em linhas msgstr (nunca em msgid ou comentários).
Preserva placeholders e marcas registadas.
Uso:
python3 fix_ptbr.py plugin-pt_PT.po [plugin2-pt_PT.po ...]
find /path/to/library -name "*-pt_PT.po" | xargs python3 fix_ptbr.py
Author: Descomplicar®
Version: 1.1.0
"""
import sys
import re
import shutil
import subprocess
from pathlib import Path
# Substituições PT-BR → PT-PT (padrão: word boundary para evitar falsos positivos)
FIXES = [
# --- Verbos ---
(r'\bsalvar\b', 'guardar'),
(r'\bSalvar\b', 'Guardar'),
(r'\bsalve\b', 'guarde'),
(r'\bSalve\b', 'Guarde'),
(r'\bativar\b', 'activar'),
(r'\bAtivar\b', 'Activar'),
(r'\bativado\b', 'activado'),
(r'\bAtivado\b', 'Activado'),
(r'\bativados\b', 'activados'),
(r'\bAtivados\b', 'Activados'),
(r'\bativada\b', 'activada'),
(r'\bAtivada\b', 'Activada'),
(r'\batualizar\b', 'actualizar'),
(r'\bAtualizar\b', 'Actualizar'),
(r'\batualização\b', 'actualização'),
(r'\bAtualização\b', 'Actualização'),
(r'\batualizações\b', 'actualizações'),
(r'\bAtualizações\b', 'Actualizações'),
(r'\bdesativar\b', 'desactivar'),
(r'\bDesativar\b', 'Desactivar'),
(r'\bdesativado\b', 'desactivado'),
(r'\bDesativado\b', 'Desactivado'),
(r'\bdesativada\b', 'desactivada'),
(r'\bDesativada\b', 'Desactivada'),
(r'\bconectar\b', 'ligar'),
(r'\bConectar\b', 'Ligar'),
(r'\bconectado\b', 'ligado'),
(r'\bConectado\b', 'Ligado'),
(r'\bdesconectar\b', 'desligar'),
(r'\bDesconectar\b', 'Desligar'),
(r'\bdesconectado\b', 'desligado'),
(r'\bDesconectado\b', 'Desligado'),
(r'\breconectar\b', 'religar'),
(r'\bReconectar\b', 'Religar'),
(r'\bselecionar\b', 'seleccionar'),
(r'\bSelecionar\b', 'Seleccionar'),
(r'\bexcluir\b', 'eliminar'),
(r'\bExcluir\b', 'Eliminar'),
(r'\bexcluído\b', 'eliminado'),
(r'\bExcluído\b', 'Eliminado'),
(r'\bexcluída\b', 'eliminada'),
(r'\bExcluída\b', 'Eliminada'),
(r'\bexcluídos\b', 'eliminados'),
(r'\bExcluídos\b', 'Eliminados'),
(r'\bexcluídas\b', 'eliminadas'),
(r'\bExcluídas\b', 'Eliminadas'),
(r'\bacessar\b', 'aceder'),
(r'\bAcessar\b', 'Aceder'),
(r'\bcompartilhar\b', 'partilhar'),
(r'\bCompartilhar\b', 'Partilhar'),
(r'\bcompartilhado\b', 'partilhado'),
(r'\bCompartilhado\b', 'Partilhado'),
(r'\bcompartilhada\b', 'partilhada'),
(r'\bCompartilhada\b', 'Partilhada'),
(r'\bcompartilhados\b', 'partilhados'),
(r'\bCompartilhados\b', 'Partilhados'),
(r'\bcompartilhadas\b', 'partilhadas'),
(r'\bCompartilhadas\b', 'Partilhadas'),
(r'\bdigite\b', 'introduza'),
(r'\bDigite\b', 'Introduza'),
# --- Substantivos ---
(r'\bsenha\b', 'palavra-passe'),
(r'\bSenha\b', 'Palavra-passe'),
(r'\bsenhas\b', 'palavras-passe'),
(r'\bSenhas\b', 'Palavras-passe'),
(r'\busuário\b', 'utilizador'),
(r'\bUsuário\b', 'Utilizador'),
(r'\busuários\b', 'utilizadores'),
(r'\bUsuários\b', 'Utilizadores'),
(r'\busuario\b', 'utilizador'),
(r'\bUsuario\b', 'Utilizador'),
(r'\barquivo\b', 'ficheiro'),
(r'\bArquivo\b', 'Ficheiro'),
(r'\barquivos\b', 'ficheiros'),
(r'\bArquivos\b', 'Ficheiros'),
(r'\bconexão\b', 'ligação'),
(r'\bConexão\b', 'Ligação'),
(r'\bseleção\b', 'selecção'),
(r'\bSeleção\b', 'Selecção'),
(r'\bselecionado\b', 'seleccionado'),
(r'\bSelecionado\b', 'Seleccionado'),
(r'\baplicativo\b', 'aplicação'),
(r'\bAplicativo\b', 'Aplicação'),
(r'\baplicativos\b', 'aplicações'),
(r'\bAplicativos\b', 'Aplicações'),
(r'\bdashboard\b', 'painel'),
(r'\bDashboard\b', 'Painel'),
(r'\bbackup\b', 'cópia de segurança'),
(r'\bBackup\b', 'Cópia de segurança'),
(r'\bbackups\b', 'cópias de segurança'),
(r'\bBackups\b', 'Cópias de segurança'),
(r'\bpostagem\b', 'publicação'),
(r'\bPostagem\b', 'Publicação'),
(r'\bpostagens\b', 'publicações'),
(r'\bPostagens\b', 'Publicações'),
(r'\bativo\b', 'activo'),
(r'\bAtivo\b', 'Activo'),
(r'\bativos\b', 'activos'),
(r'\bAtivos\b', 'Activos'),
(r'\bativa\b', 'activa'),
(r'\bAtiva\b', 'Activa'),
(r'\bativas\b', 'activas'),
(r'\bAtivas\b', 'Activas'),
(r'\binativo\b', 'inactivo'),
(r'\bInativo\b', 'Inactivo'),
(r'\binativos\b', 'inactivos'),
(r'\bInativos\b', 'Inactivos'),
(r'\binativa\b', 'inactiva'),
(r'\bInativa\b', 'Inactiva'),
(r'\binativas\b', 'inactivas'),
(r'\bInativas\b', 'Inactivas'),
(r'\bativação\b', 'activação'),
(r'\bAtivação\b', 'Activação'),
(r'\bdesativação\b', 'desactivação'),
(r'\bDesativação\b', 'Desactivação'),
# --- Ortografia PT-PT ---
# Formas garbled LibreTranslate (Updated→Atualizard, Updates→Atualizars)
(r'\bAtualizard\b', 'Actualizado'),
(r'\batualizard\b', 'actualizado'),
(r'\bAtualizars\b', 'Actualizações'),
(r'\batualizars\b', 'actualizações'),
# Formas maiúsculas (all-caps)
(r'\bATUALIZAR\b', 'ACTUALIZAR'),
(r'\bATUALIZAÇÃO\b', 'ACTUALIZAÇÃO'),
(r'\bATIVAR\b', 'ACTIVAR'),
(r'\bDESATIVAR\b', 'DESACTIVAR'),
(r'\bATIVADO\b', 'ACTIVADO'),
(r'\bDESATIVADO\b', 'DESACTIVADO'),
(r'\bARQUIVO\b', 'FICHEIRO'),
(r'\bARQUIVOS\b', 'FICHEIROS'),
# Todas as formas de atualiz* → actualiz*
(r'\batualizada\b', 'actualizada'),
(r'\bAtualizada\b', 'Actualizada'),
(r'\batualizadas\b', 'actualizadas'),
(r'\bAtualizadas\b', 'Actualizadas'),
(r'\batualizado\b', 'actualizado'),
(r'\bAtualizado\b', 'Actualizado'),
(r'\batualizados\b', 'actualizados'),
(r'\bAtualizados\b', 'Actualizados'),
(r'\batualize\b', 'actualize'),
(r'\bAtualize\b', 'Actualize'),
(r'\batualiza\b', 'actualiza'),
(r'\bAtualiza\b', 'Actualiza'),
(r'\batualizando\b', 'actualizando'),
(r'\bAtualizando\b', 'Actualizando'),
(r'\batualizou\b', 'actualizou'),
(r'\bAtualizou\b', 'Actualizou'),
(r'\batualizem\b', 'actualizem'),
(r'\bAtualizem\b', 'Actualizem'),
(r'\batualizam\b', 'actualizam'),
(r'\bAtualizam\b', 'Actualizam'),
(r'\batualizamos\b', 'actualizamos'),
(r'\bAtualizamos\b', 'Actualizamos'),
(r'\batualizei\b', 'actualizei'),
(r'\bAtualizei\b', 'Actualizei'),
(r'\batualizará\b', 'actualizará'),
(r'\bAtualizará\b', 'Actualizará'),
(r'\batualizarão\b', 'actualizarão'),
(r'\bAtualizarão\b', 'Actualizarão'),
(r'\batualizarei\b', 'actualizarei'),
(r'\bAtualizarei\b', 'Actualizarei'),
(r'\batualizaremos\b', 'actualizaremos'),
(r'\bAtualizaremos\b', 'Actualizaremos'),
(r'\batualizarás\b', 'actualizarás'),
(r'\batualizassem\b', 'actualizassem'),
# Formas com acento (atualizá-los, atualizá-la)
(r'\batualizá\b', 'actualizá'),
(r'\bAtualizá\b', 'Actualizá'),
# Habilitar/desabilitar → activar/desactivar
(r'\bhabilitado\b', 'activado'),
(r'\bHabilitado\b', 'Activado'),
(r'\bhabilitada\b', 'activada'),
(r'\bHabilitada\b', 'Activada'),
(r'\bhabilitados\b', 'activados'),
(r'\bHabilitados\b', 'Activados'),
(r'\bhabilitadas\b', 'activadas'),
(r'\bHabilitadas\b', 'Activadas'),
(r'\bhabilitar\b', 'activar'),
(r'\bHabilitar\b', 'Activar'),
(r'\bdesabilitado\b', 'desactivado'),
(r'\bDesabilitado\b', 'Desactivado'),
(r'\bdesabilitada\b', 'desactivada'),
(r'\bDesabilitada\b', 'Desactivada'),
(r'\bdesabilitados\b', 'desactivados'),
(r'\bDesabilitados\b', 'Desactivados'),
(r'\bdesabilitar\b', 'desactivar'),
(r'\bDesabilitar\b', 'Desactivar'),
(r'\bdesabilitadas\b', 'desactivadas'),
(r'\bDesabilitadas\b', 'Desactivadas'),
# Formas plurais de desativar
(r'\bdesativados\b', 'desactivados'),
(r'\bDesativados\b', 'Desactivados'),
(r'\bdesativadas\b', 'desactivadas'),
(r'\bDesativadas\b', 'Desactivadas'),
(r'\bdesativando\b', 'desactivando'),
(r'\bDesativando\b', 'Desactivando'),
# Formas plurais de ativar
(r'\bativados\b', 'activados'),
(r'\bAtivados\b', 'Activados'),
(r'\bativadas\b', 'activadas'),
(r'\bAtivadas\b', 'Activadas'),
(r'\bativando\b', 'activando'),
(r'\bAtivando\b', 'Activando'),
(r'\bfatura\b', 'factura'),
(r'\bFatura\b', 'Factura'),
(r'\bfaturas\b', 'facturas'),
(r'\bFaturas\b', 'Facturas'),
(r'\bfacturar\b', 'facturar'),
(r'\bóptico\b', 'óptico'),
(r'\bótimo\b', 'óptimo'),
(r'\bÓtimo\b', 'Óptimo'),
(r'\bação\b', 'acção'),
(r'\bAção\b', 'Acção'),
(r'\bações\b', 'acções'),
(r'\bAções\b', 'Acções'),
(r'\bdireito\b', 'direito'), # igual — sem alteração necessária
(r'\bdiretamente\b', 'directamente'),
(r'\bDiretamente\b', 'Directamente'),
(r'\bdireto\b', 'directo'),
(r'\bDireto\b', 'Directo'),
(r'\bcontacto\b', 'contacto'), # já correcto
# --- Pronomes PT-BR ---
(r'\bVOCÊ\b', 'SI'),
(r'\bVOCÊS\b', 'VÓS'),
(r'\bvocê\b', 'o utilizador'),
(r'\bVocê\b', 'O utilizador'),
(r'\bvocês\b', 'os utilizadores'),
(r'\bVocês\b', 'Os utilizadores'),
# --- Expressões compostas ---
(r'\bsua conta\b', 'a sua conta'),
(r'\bSua conta\b', 'A sua conta'),
(r'\bnome de usuário\b', 'nome de utilizador'),
(r'\bNome de usuário\b', 'Nome de utilizador'),
(r'\bnome de usuario\b', 'nome de utilizador'),
]
def fix_line(line: str) -> str:
"""Aplica todas as substituições PT-BR → PT-PT numa linha."""
result = line
for pattern, replacement in FIXES:
result = re.sub(pattern, replacement, result)
return result
def process_file(filepath: str) -> tuple[int, bool]:
"""
Processa um ficheiro .po e corrige PT-BR → PT-PT.
Devolve (número de correcções, sucesso do .mo).
"""
path = Path(filepath)
if not path.exists():
print(f" ERRO: ficheiro não encontrado: {filepath}", file=sys.stderr)
return 0, False
with open(filepath, 'r', encoding='utf-8') as f:
lines = f.readlines()
new_lines = []
in_msgstr = False
fixes = 0
for line in lines:
stripped = line.rstrip('\n')
if stripped.startswith('msgstr ') or re.match(r'^msgstr\[\d+\]', stripped):
in_msgstr = True
fixed = fix_line(stripped)
if fixed != stripped:
fixes += 1
new_lines.append(fixed + '\n')
elif stripped.startswith('"') and in_msgstr:
fixed = fix_line(stripped)
if fixed != stripped:
fixes += 1
new_lines.append(fixed + '\n')
else:
if not stripped or stripped.startswith('#') or \
stripped.startswith('msgid') or stripped.startswith('msgctxt'):
in_msgstr = False
new_lines.append(line)
if fixes > 0:
shutil.copy2(filepath, filepath + '.bak_ptbr')
with open(filepath, 'w', encoding='utf-8') as f:
f.writelines(new_lines)
mo_path = filepath.replace('.po', '.mo')
r = subprocess.run(
['msgfmt', filepath, '-o', mo_path],
stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
mo_ok = r.returncode == 0
mo_status = "OK" if mo_ok else f"ERRO: {r.stderr.decode()[:80]}"
print(f" {path.name}: {fixes} correcção(ões) PT-BR | .mo: {mo_status}")
return fixes, mo_ok
else:
print(f" {path.name}: sem PT-BR detectado")
return 0, True
def main():
if len(sys.argv) < 2:
print("Uso: python3 fix_ptbr.py <ficheiro.po> [...]")
print(" find /path -name '*-pt_PT.po' | xargs python3 fix_ptbr.py")
sys.exit(1)
total_fixes = 0
total_files = 0
errors = 0
for filepath in sys.argv[1:]:
total_files += 1
fixes, ok = process_file(filepath)
total_fixes += fixes
if not ok:
errors += 1
print(f"\nTotal: {total_fixes} correcção(ões) em {total_files} ficheiro(s) | Erros .mo: {errors}")
if __name__ == '__main__':
main()