feat(i18n): Spanish localization (phase 4)
CI / Lint e auditorias (push) Successful in 1m31s
CI / Trivy (dependências e segredos) (push) Successful in 10s
CI / Imagem Docker (linux/arm64) (push) Successful in 2m23s

Complete implementation of Spanish (es-419) language support:
- Canonical catalogs and data: messages/es.json, data/es/**, lib/data/es/**, public/exemplos/es/**
- Canonical slugs: /es/series, /es/catalogo, /es/comparacion, /es/componentes, /es/diagnostico, /es/frameworks, /es/glosario, /es/selector, /es/acerca
- Dedicated search index at /api/busca/es with Spanish accent normalization
- Strict exclusion of book references in Spanish routes and catalogs
- Language selector and root negotiation with es active (ENABLED_LOCALES = ['pt', 'en', 'es'])
- Extended verification suite: check-i18n, smoke-imagem and verifica-vazamentos

Co-Authored-By: Antigravity <noreply@google.com>
This commit is contained in:
Lucas RayanandAntigravity committed 2026-11-01 19:50:20 -03:00
1 parent 0940814522
commit 660b28c09d
72 files changed
+17848 -947

No files matched your search

+16 -6
View File
@@ -24,6 +24,13 @@ const CAMINHOS_EN = [
{ href: "/glossario", icon: BookOpen, titulo: "Glossary", texto: "Hardware terms explained clearly." },
];
const CAMINHOS_ES = [
{ href: "/series", icon: Compass, titulo: "Series ESP32", texto: "Las 12 familias, con patillaje y especificaciones." },
{ href: "/seletor", icon: SlidersHorizontal, titulo: "Selector de chip", texto: "Responda a ocho preguntas y reciba los modelos recomendados." },
{ href: "/comparacao", icon: Scale, titulo: "Comparador", texto: "Hasta cuatro series frente a frente." },
{ href: "/glossario", icon: BookOpen, titulo: "Glosario", texto: "Términos de hardware explicados con claridad." },
];
export default async function NotFound() {
let locale = "pt";
try {
@@ -32,7 +39,8 @@ export default async function NotFound() {
locale = "pt";
}
const isEn = locale === "en";
const caminhos = isEn ? CAMINHOS_EN : CAMINHOS_PT;
const isEs = locale === "es";
const caminhos = isEn ? CAMINHOS_EN : isEs ? CAMINHOS_ES : CAMINHOS_PT;
return (
<div className="site-canvas min-h-screen">
@@ -40,16 +48,18 @@ export default async function NotFound() {
<main id="conteudo" className="shell section">
<div className="mx-auto max-w-2xl text-center">
<p className="eyebrow justify-center">{isEn ? "Error 404" : "Erro 404"}</p>
<h1 className="page-title mt-4">{isEn ? "This page does not exist." : "Essa página não existe."}</h1>
<p className="eyebrow justify-center">{isEn ? "Error 404" : "Error 404"}</p>
<h1 className="page-title mt-4">{isEn ? "This page does not exist." : isEs ? "Esta página no existe." : "Essa página não existe."}</h1>
<p className="lede mx-auto mt-5 max-w-xl">
{isEn
? "The address may have changed or was mistyped. Choose one of these paths to continue."
: isEs
? "La dirección puede haber cambiado o estar mal escrita. Elija uno de estos caminos para continuar."
: "O endereço pode ter mudado ou estar digitado errado. Escolha um destes caminhos para continuar."}
</p>
<div className="mt-8 flex justify-center">
<Link href={isEn ? "/en" : "/"} className="btn btn-primary">
{isEn ? "Back to home" : "Voltar ao início"}
<Link href={isEn ? "/en" : isEs ? "/es" : "/"} className="btn btn-primary">
{isEn ? "Back to home" : isEs ? "Volver al inicio" : "Voltar ao início"}
<ArrowRight className="h-4 w-4" aria-hidden="true" />
</Link>
</div>
@@ -57,7 +67,7 @@ export default async function NotFound() {
<ul className="mx-auto mt-14 grid max-w-4xl gap-3 sm:grid-cols-2">
{caminhos.map(({ href, icon: Icon, titulo, texto }) => {
const targetHref = isEn ? getLocalizedHref(href, "en") : href;
const targetHref = getLocalizedHref(href, locale);
return (
<li key={href}>
<Link href={targetHref} className="card card-interactive group flex h-full items-start gap-4 p-5">