feat(i18n): Simplified Chinese (zh-CN), search answers per locale, fr/de/es data fixes
CI / Lint e auditorias (push) Successful in 1m10s
CI / Trivy (dependências e segredos) (push) Successful in 12s
CI / Imagem Docker (linux/arm64) (push) Successful in 2m39s
Release / Plano (reaproveitar a imagem?) (push) Successful in 6s
Release / ci (push) Skipped
Release / Publica a imagem (linux/arm64) (push) Successful in 18s
Release / Cria a release no Gitea (push) Successful in 5s

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas RayanandClaude Sonnet 5.5 committed 2026-11-01 23:28:39 -03:00
1 parent ae61416468
commit 5a9fe676fc
61 files changed
+2517 -920

No files matched your search

+65 -1
View File
@@ -235,8 +235,72 @@ for u in urls_de:
print(f" ✖ Texto visível vazamento em {u}: \"{h[:120]}\"")
falhas += 1
# Varredura das rotas em chinês simplificado: português OU inglês solto (fora de blocos de código)
pt_in_zh_regex = re.compile(
r"\b(não|você|para o|para a|com o|com a|são|também|então|pinagem|série|séries|livro|"
r"ção|ções|muito|já|estão|é um|é uma|pelo|pela|especificações|especificação|início|artigo|sobre|seletor)\b",
re.I
)
# Frase em inglês solta: palavra funcional entre palavras minúsculas, ou expressões de interface.
# Nomes de produto em Title Case ("Arduino Core for ESP32", "Google Home") não casam.
en_in_zh_regex = re.compile(
r"\b[a-z]{2,}\s+(?:the|and|with|for|your|this|that|from|are|you|will|not|how|what)\s+[a-z]{2,}\b"
r"|(?i:\b(?:skip to content|click here|learn more|read more|back to|please)\b)"
)
fixas_zh = [
"/zh-CN", "/zh-CN/series", "/zh-CN/compare", "/zh-CN/diagnostics", "/zh-CN/selector",
"/zh-CN/frameworks", "/zh-CN/components", "/zh-CN/glossary", "/zh-CN/catalog", "/zh-CN/about"
]
urls_zh = fixas_zh + [f"/zh-CN/series/{s}" for s in series] + [f"/zh-CN/frameworks/{f}" for f in frameworks]
print(f"\nESPDocs · Varredura de i18n nas {len(urls_zh)} rotas em chinês ({base})")
# Mensagens reais de log/erro da ferramenta: aparecem iguais em qualquer idioma.
ASSINATURAS_DE_LOG = {"Failed to connect to ESP32: Timed out waiting for packet header"}
def vazou_zh(texto):
if texto.strip() in ASSINATURAS_DE_LOG:
return None
return pt_in_zh_regex.search(texto) or en_in_zh_regex.search(texto)
for u in urls_zh:
try:
req = urllib.request.Request(base + u, headers={"User-Agent": "ESPDocs-SmokeTest/1.0"})
raw = urllib.request.urlopen(req, timeout=10).read().decode("utf-8")
except Exception as e:
print(f" ✖ ERRO ao acessar {u}: {e}")
falhas += 1
continue
# <html lang> correto
if not re.search(r"<html[^>]*\blang=\"zh-CN\"", raw):
print(f" ✖ <html lang> diferente de zh-CN em {u}")
falhas += 1
# 1. Verifica blocos ld+json (strings de texto, não URLs/ids)
scripts = re.findall(r"<script[^>]*type=[\"']application/ld\+json[\"'][^>]*>(.*?)</script>", raw, re.DOTALL)
for i, s in enumerate(scripts):
try:
data = json.loads(s)
issues = check_jsonld(data, f"script[{i}]", pt_in_zh_regex, True)
for p_, v in issues:
print(f" ✖ JSON-LD vazamento em {u} -> {p_}: \"{v}\"")
falhas += 1
except Exception as e:
print(f" ✖ Erro no parse de JSON-LD em {u}: {e}")
falhas += 1
# 2. Texto visível, sem blocos de código (exemplos têm logs e comentários em inglês por desenho)
clean = re.sub(r"<(script|style|pre|code)[\s\S]*?</\1>", "", raw)
clean = html.unescape(re.sub(r"<[^>]+>", "\n", clean))
hits = [l.strip() for l in clean.split("\n") if l.strip() and vazou_zh(l)]
for h in hits:
print(f" ✖ Texto visível vazamento em {u}: \"{h[:120]}\"")
falhas += 1
if falhas == 0:
print(f" ✔ Todas as {len(urls)} rotas en, {len(urls_es)} rotas es, {len(urls_fr)} rotas fr e {len(urls_de)} rotas de verificadas com ZERO vazamentos (texto e JSON-LD).")
print(f" ✔ Todas as {len(urls)} rotas en, {len(urls_es)} rotas es, {len(urls_fr)} rotas fr, {len(urls_de)} rotas de e {len(urls_zh)} rotas zh verificadas com ZERO vazamentos (texto e JSON-LD).")
sys.exit(0)
else:
print(f" ✖ Total de falhas detectadas: {falhas}")