- Add full message catalogs and content for French (fr) and German (de) - Implement ASCII canonical slugs for French and German routes - Add language-specific search endpoints (/api/busca/fr, /api/busca/de) - Configure strict 404 responses for /fr/livro and /de/livro - Localize SEO, OpenGraph (fr_FR, de_DE), Twitter and JSON-LD schemas - Add localized code example comments across 14 examples for fr and de - Enable 'fr' and 'de' in ENABLED_LOCALES with root negotiation and redirect - Extend test suite in check-i18n, smoke-imagem and verifica-vazamentos Co-Authored-By: Antigravity <noreply@google.com>
180 lines
6.5 KiB
Bash
Executable File
180 lines
6.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Teste de fumaça do servidor: rotas por idioma, redirects e regras do livro.
|
|
#
|
|
# scripts/smoke-imagem.sh http://127.0.0.1:3998
|
|
#
|
|
# Cada falha é impressa e o script sai com 1 no fim, para mostrar tudo de uma vez.
|
|
set -uo pipefail
|
|
|
|
base=${1:?uso: smoke-imagem.sh <url-base>}
|
|
falhas=0
|
|
|
|
# status <esperado> <caminho> [cabeçalho]
|
|
status() {
|
|
local got
|
|
got=$(curl -s -o /dev/null -w '%{http_code}' ${3:+-H "$3"} "$base$2")
|
|
[ "$got" = "$1" ] || { echo "FALHOU $2 ${3:-}: esperado $1, veio $got"; falhas=$((falhas + 1)); }
|
|
}
|
|
|
|
# destino <status> <caminho> <redirecionamento esperado> [cabeçalho]
|
|
destino() {
|
|
local out
|
|
out=$(curl -s -o /dev/null -w '%{http_code} %{redirect_url}' ${4:+-H "$4"} "$base$2")
|
|
[ "$out" = "$1 $base$3" ] || { echo "FALHOU $2 ${4:-}: esperado '$1 $3', veio '${out#* }'" ; falhas=$((falhas + 1)); }
|
|
}
|
|
|
|
# O servidor leva alguns segundos para subir.
|
|
for _ in $(seq 1 30); do curl -fsS -o /dev/null "$base/pt" && break; sleep 2; done
|
|
|
|
# Lista de idiomas ativos lida dinamicamente do módulo i18n/links.js
|
|
ENABLED_LOCALES=${ENABLED_LOCALES:-$(node -e 'import("./i18n/links.js").then(m => console.log(m.ENABLED_LOCALES.join(" ")))' 2>/dev/null || echo "pt")}
|
|
ALL_LOCALES="pt en es fr de zh-CN"
|
|
|
|
FALLBACK_LOCALE="pt"
|
|
if [[ " $ENABLED_LOCALES " =~ " en " ]]; then
|
|
FALLBACK_LOCALE="en"
|
|
fi
|
|
|
|
# 1. Páginas que existem em todos os idiomas ATIVOS
|
|
for l in $ENABLED_LOCALES; do
|
|
status 200 "/$l"
|
|
done
|
|
for p in /series /sobre /livro; do
|
|
status 200 "/pt$p"
|
|
done
|
|
|
|
if [[ " $ENABLED_LOCALES " =~ " en " ]]; then
|
|
for p in /series /catalog /compare /components /diagnostics /frameworks /glossary /selector /about; do
|
|
status 200 "/en$p"
|
|
done
|
|
fi
|
|
|
|
if [[ " $ENABLED_LOCALES " =~ " es " ]]; then
|
|
for p in /series /catalogo /comparacion /componentes /diagnostico /frameworks /glosario /selector /acerca; do
|
|
status 200 "/es$p"
|
|
done
|
|
fi
|
|
|
|
if [[ " $ENABLED_LOCALES " =~ " fr " ]]; then
|
|
for p in /series /catalogue /comparaison /composants /diagnostic /frameworks /glossaire /selecteur /a-propos; do
|
|
status 200 "/fr$p"
|
|
done
|
|
fi
|
|
|
|
if [[ " $ENABLED_LOCALES " =~ " de " ]]; then
|
|
for p in /serien /katalog /vergleich /komponenten /diagnose /frameworks /glossar /auswahl /ueber-uns; do
|
|
status 200 "/de$p"
|
|
done
|
|
fi
|
|
|
|
# 2. Idiomas INATIVOS: redirecionam com 307 para o idioma fallback (en se ativo, senão pt)
|
|
for l in $ALL_LOCALES; do
|
|
if [[ ! " $ENABLED_LOCALES " =~ " $l " ]]; then
|
|
destino 307 "/$l" "/$FALLBACK_LOCALE"
|
|
destino 307 "/$l/series" "/$FALLBACK_LOCALE/series"
|
|
if [ "$FALLBACK_LOCALE" = "en" ]; then
|
|
destino 307 "/$l/livro" "/en"
|
|
else
|
|
destino 307 "/$l/livro" "/pt/livro"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
# 3. Negociação de idioma na raiz (deve considerar apenas ativos)
|
|
if [[ " $ENABLED_LOCALES " == " pt " ]]; then
|
|
# Com só pt ativo, todo Accept-Language e cookie de idioma inativo cai em /pt
|
|
destino 307 / /pt 'Accept-Language: pt-BR,pt;q=0.9'
|
|
destino 307 / /pt 'Accept-Language: es-MX,es;q=0.9,en;q=0.5'
|
|
destino 307 / /pt 'Accept-Language: fr-CA,fr;q=0.9'
|
|
destino 307 / /pt 'Accept-Language: de-AT,de;q=0.8'
|
|
destino 307 / /pt 'Accept-Language: zh-CN,zh;q=0.9'
|
|
destino 307 / /pt 'Accept-Language: it-IT'
|
|
destino 307 / /pt 'Accept-Language: en;q=0.5,pt;q=0.9'
|
|
destino 307 / /pt 'Cookie: NEXT_LOCALE=es'
|
|
else
|
|
destino 307 / /pt 'Accept-Language: pt-BR,pt;q=0.9'
|
|
destino 307 / /en 'Accept-Language: en-US,en;q=0.9'
|
|
destino 307 / /en 'Accept-Language: it-IT'
|
|
destino 307 / /pt 'Accept-Language: en;q=0.5,pt;q=0.9'
|
|
destino 307 / /pt 'Cookie: NEXT_LOCALE=pt'
|
|
destino 307 / /en 'Cookie: NEXT_LOCALE=en'
|
|
# Idiomas inativos negociam para fallback (en)
|
|
if [[ ! " $ENABLED_LOCALES " =~ " es " ]]; then
|
|
destino 307 / /en 'Accept-Language: es-MX,es;q=0.9'
|
|
destino 307 / /en 'Cookie: NEXT_LOCALE=es'
|
|
else
|
|
destino 307 / /es 'Accept-Language: es-MX,es;q=0.9'
|
|
destino 307 / /es 'Cookie: NEXT_LOCALE=es'
|
|
fi
|
|
if [[ ! " $ENABLED_LOCALES " =~ " fr " ]]; then
|
|
destino 307 / /en 'Accept-Language: fr-CA,fr;q=0.9'
|
|
else
|
|
destino 307 / /fr 'Accept-Language: fr-FR,fr;q=0.9'
|
|
destino 307 / /fr 'Cookie: NEXT_LOCALE=fr'
|
|
fi
|
|
if [[ ! " $ENABLED_LOCALES " =~ " de " ]]; then
|
|
destino 307 / /en 'Accept-Language: de-AT,de;q=0.8'
|
|
else
|
|
destino 307 / /de 'Accept-Language: de-DE,de;q=0.9'
|
|
destino 307 / /de 'Cookie: NEXT_LOCALE=de'
|
|
fi
|
|
if [[ ! " $ENABLED_LOCALES " =~ " zh-CN " ]]; then
|
|
destino 307 / /en 'Accept-Language: zh-CN,zh;q=0.9'
|
|
fi
|
|
fi
|
|
|
|
# 4. URLs antigas (sem prefixo) continuam 308 permanente para /pt/...
|
|
destino 308 /series/ESP32-S3 /pt/series/ESP32-S3 'Accept-Language: en-US'
|
|
destino 308 /livro /pt/livro 'Accept-Language: en-US'
|
|
|
|
# 5. O livro dá 404 apenas em idiomas ATIVOS que não sejam pt
|
|
for l in $ENABLED_LOCALES; do
|
|
if [ "$l" != "pt" ]; then
|
|
status 404 "/$l/livro"
|
|
fi
|
|
done
|
|
|
|
# 6. Metadata no <head> inicial (title, canonical), para qualquer cliente
|
|
html=$(curl -s -A 'Mozilla/5.0 Chrome/130' "$base/pt/sobre")
|
|
head=${html%%</head>*}
|
|
for marca in '<title>' 'rel="canonical"'; do
|
|
case "$head" in *"$marca"*) ;; *) echo "FALHOU /pt/sobre: $marca fora do <head>"; falhas=$((falhas + 1));; esac
|
|
done
|
|
|
|
if [[ " $ENABLED_LOCALES " =~ " en " ]]; then
|
|
html_en=$(curl -s -A 'Mozilla/5.0 Chrome/130' "$base/en/about")
|
|
head_en=${html_en%%</head>*}
|
|
for marca in '<title>' 'rel="canonical"'; do
|
|
case "$head_en" in *"$marca"*) ;; *) echo "FALHOU /en/about: $marca fora do <head>"; falhas=$((falhas + 1));; esac
|
|
done
|
|
|
|
# 7. Varredura estrita contra vazamento de português (texto visível e blocos ld+json) nas rotas inglesas e espanholas
|
|
python3 scripts/verifica-vazamentos.py "$base" || falhas=$((falhas + 1))
|
|
fi
|
|
|
|
if [[ " $ENABLED_LOCALES " =~ " es " ]]; then
|
|
html_es=$(curl -s -A 'Mozilla/5.0 Chrome/130' "$base/es/acerca")
|
|
head_es=${html_es%%</head>*}
|
|
for marca in '<title>' 'rel="canonical"'; do
|
|
case "$head_es" in *"$marca"*) ;; *) echo "FALHOU /es/acerca: $marca fora do <head>"; falhas=$((falhas + 1));; esac
|
|
done
|
|
fi
|
|
|
|
if [[ " $ENABLED_LOCALES " =~ " fr " ]]; then
|
|
html_fr=$(curl -s -A 'Mozilla/5.0 Chrome/130' "$base/fr/a-propos")
|
|
head_fr=${html_fr%%</head>*}
|
|
for marca in '<title>' 'rel="canonical"'; do
|
|
case "$head_fr" in *"$marca"*) ;; *) echo "FALHOU /fr/a-propos: $marca fora do <head>"; falhas=$((falhas + 1));; esac
|
|
done
|
|
fi
|
|
|
|
if [[ " $ENABLED_LOCALES " =~ " de " ]]; then
|
|
html_de=$(curl -s -A 'Mozilla/5.0 Chrome/130' "$base/de/ueber-uns")
|
|
head_de=${html_de%%</head>*}
|
|
for marca in '<title>' 'rel="canonical"'; do
|
|
case "$head_de" in *"$marca"*) ;; *) echo "FALHOU /de/ueber-uns: $marca fora do <head>"; falhas=$((falhas + 1));; esac
|
|
done
|
|
fi
|
|
|
|
exit $((falhas > 0))
|