feat(i18n): English localization (phase 3)
- Translate content to English across messages/en.json, data/en, lib/data/en, and public/exemplos/en - Implement localized routing, slugs, and language negotiation with fallback to en - Build dedicated search index for English with strict book exclusion - Update components and pages to dynamically render localized strings and datasets - Verify full structural parity and exact 1:1 match on Portuguese pages via comparator Co-Authored-By: Antigravity <noreply@google.com>
This commit is contained in:
1 parent
22b1f26aed
commit
c1bd2c7e11
61 files changed
+18182
-1225
No files matched your search
+60
-17
@@ -1,9 +1,17 @@
|
||||
import seriesData from "@/public/series.json";
|
||||
import frameworksData from "@/public/frameworks.json";
|
||||
import { categoriasGlossario } from "@/lib/glossarioData";
|
||||
import { errosCatalogo } from "@/lib/diagnosticoData";
|
||||
import { COMPONENTES_REGISTRY } from "@/lib/componentRegistryData";
|
||||
import { montarConhecimento } from "@/lib/searchTopics";
|
||||
import seriesDataPt from "@/public/series.json";
|
||||
import frameworksDataPt from "@/public/frameworks.json";
|
||||
import { categoriasGlossario as glossarioPt } from "@/lib/glossarioData";
|
||||
import { errosCatalogo as errosPt } from "@/lib/diagnosticoData";
|
||||
import { COMPONENTES_REGISTRY as componentesPt } from "@/lib/componentRegistryData";
|
||||
import { montarConhecimento as montarConhecimentoPt } from "@/lib/searchTopics";
|
||||
|
||||
import seriesDataEn from "@/data/en/series.json";
|
||||
import frameworksDataEn from "@/data/en/frameworks.json";
|
||||
import { categoriasGlossario as glossarioEn } from "@/lib/data/en/glossario";
|
||||
import { errosCatalogo as errosEn } from "@/lib/data/en/diagnostico";
|
||||
import { COMPONENTES_REGISTRY as componentesEn } from "@/lib/data/en/componentes";
|
||||
import { montarConhecimento as montarConhecimentoEn } from "@/lib/data/en/topicos";
|
||||
|
||||
import { readFileSync, existsSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
@@ -15,7 +23,7 @@ import path from "node:path";
|
||||
* `keywords` guarda texto extra pesquisável (não exibido).
|
||||
*/
|
||||
|
||||
const PAGINAS = [
|
||||
const PAGINAS_PT = [
|
||||
{ titulo: "Início", descricao: "Página inicial do ESPDocs", href: "/", keywords: "home inicio" },
|
||||
{ titulo: "Todas as Séries", descricao: "Pinouts, especificações e restrições de cada série ESP32", href: "/series", keywords: "chips pinout especificações" },
|
||||
{ titulo: "Comparador de Séries", descricao: "Compare até 4 modelos lado a lado", href: "/comparacao", keywords: "comparar comparação versus" },
|
||||
@@ -29,12 +37,41 @@ const PAGINAS = [
|
||||
{ titulo: "Sobre o Projeto", descricao: "História, autor e Ciência Embarcada", href: "/sobre", keywords: "autor contato" },
|
||||
];
|
||||
|
||||
const PAGINAS_EN = [
|
||||
{ titulo: "Home", descricao: "ESPDocs homepage", href: "/en", keywords: "home" },
|
||||
{ titulo: "All Series", descricao: "Pinouts, specifications and restrictions for each ESP32 series", href: "/en/series", keywords: "chips pinout specifications" },
|
||||
{ titulo: "Series Comparator", descricao: "Compare up to 4 models side by side", href: "/en/compare", keywords: "compare comparison versus" },
|
||||
{ titulo: "Board Catalog", descricao: "Development boards, pinouts and purchasing", href: "/en/catalog", keywords: "boards dev boards devkit buy" },
|
||||
{ titulo: "Smart Selector", descricao: "Find the ideal chip for your project", href: "/en/selector", keywords: "quiz choose recommend selector" },
|
||||
{ titulo: "Error Diagnostics", descricao: "Troubleshoot brownout, bootloop, WDT and crashes", href: "/en/diagnostics", keywords: "error problem bug crash issue" },
|
||||
{ titulo: "Frameworks & SDKs", descricao: "ESP-IDF, Arduino, Rust, RainMaker and more", href: "/en/frameworks", keywords: "sdk" },
|
||||
{ titulo: "Component Registry", descricao: "Driver catalog and idf_component.yml generator", href: "/en/components", keywords: "libraries drivers yml components" },
|
||||
{ titulo: "Technical Glossary", descricao: "Essential hardware and software concepts", href: "/en/glossary", keywords: "terms dictionary definition meaning" },
|
||||
{ titulo: "About the Project", descricao: "History, author and open source", href: "/en/about", keywords: "author contact" },
|
||||
];
|
||||
|
||||
const cortar = (texto = "", max = 140) => (texto.length > max ? `${texto.slice(0, max - 1).trimEnd()}…` : texto);
|
||||
|
||||
export function construirIndiceBusca() {
|
||||
export function construirIndiceBusca(locale = "pt") {
|
||||
const isEn = locale === "en";
|
||||
const paginas = isEn ? PAGINAS_EN : PAGINAS_PT;
|
||||
const seriesData = isEn ? seriesDataEn : seriesDataPt;
|
||||
const frameworksData = isEn ? frameworksDataEn : frameworksDataPt;
|
||||
const categoriasGlossario = isEn ? glossarioEn : glossarioPt;
|
||||
const errosCatalogo = isEn ? errosEn : errosPt;
|
||||
const componentes = isEn ? componentesEn : componentesPt;
|
||||
const montarConhecimento = isEn ? montarConhecimentoEn : montarConhecimentoPt;
|
||||
|
||||
const prefixo = isEn ? "/en" : "";
|
||||
const slugSeries = `${prefixo}/series`;
|
||||
const slugFrameworks = `${prefixo}/frameworks`;
|
||||
const slugGlossario = isEn ? "/en/glossary" : "/glossario";
|
||||
const slugDiagnostico = isEn ? "/en/diagnostics" : "/diagnostico";
|
||||
const slugComponentes = isEn ? "/en/components" : "/componentes";
|
||||
|
||||
const itens = [];
|
||||
|
||||
for (const p of PAGINAS) {
|
||||
for (const p of paginas) {
|
||||
itens.push({ tipo: "pagina", ...p, keywords: p.keywords });
|
||||
}
|
||||
|
||||
@@ -43,7 +80,7 @@ export function construirIndiceBusca() {
|
||||
tipo: "serie",
|
||||
titulo: chave,
|
||||
descricao: cortar(`${s.nome_completo ?? ""} — ${s.descricao ?? ""}`),
|
||||
href: `/series/${chave}`,
|
||||
href: `${slugSeries}/${chave}`,
|
||||
keywords: [s.arquitetura, s.wifi, s.bluetooth, s.frequencia, s.nucleos].filter(Boolean).join(" "),
|
||||
});
|
||||
}
|
||||
@@ -53,7 +90,7 @@ export function construirIndiceBusca() {
|
||||
tipo: "framework",
|
||||
titulo: f.nome ?? chave,
|
||||
descricao: cortar(`${f.nome_completo ?? ""} — ${f.descricao ?? ""}`),
|
||||
href: `/frameworks/${encodeURIComponent(chave)}`,
|
||||
href: `${slugFrameworks}/${encodeURIComponent(chave)}`,
|
||||
keywords: [f.linguagem, f.tipo, f.funcao_principal].filter(Boolean).join(" "),
|
||||
});
|
||||
}
|
||||
@@ -65,7 +102,7 @@ export function construirIndiceBusca() {
|
||||
tipo: "glossario",
|
||||
titulo: t.termo,
|
||||
descricao: cortar(t.definicao),
|
||||
href: `/glossario#${slug}`,
|
||||
href: `${slugGlossario}#${slug}`,
|
||||
keywords: [cat.nome, t.exemplo].filter(Boolean).join(" "),
|
||||
});
|
||||
}
|
||||
@@ -76,25 +113,31 @@ export function construirIndiceBusca() {
|
||||
tipo: "erro",
|
||||
titulo: e.titulo,
|
||||
descricao: cortar(e.resumo),
|
||||
href: `/diagnostico#${e.id}`,
|
||||
href: `${slugDiagnostico}#${e.id}`,
|
||||
keywords: [e.logSerial, ...(e.sintomas ?? [])].filter(Boolean).join(" "),
|
||||
});
|
||||
}
|
||||
|
||||
for (const c of COMPONENTES_REGISTRY) {
|
||||
for (const c of componentes) {
|
||||
itens.push({
|
||||
tipo: "componente",
|
||||
titulo: c.titulo,
|
||||
descricao: cortar(c.descricao),
|
||||
href: "/componentes",
|
||||
href: slugComponentes,
|
||||
keywords: [c.name, c.namespace, ...(c.tags ?? [])].filter(Boolean).join(" "),
|
||||
});
|
||||
}
|
||||
|
||||
const conexoes = {};
|
||||
for (const chave of Object.keys(seriesData)) {
|
||||
const arquivo = path.join(process.cwd(), "public", "conexoes", `${chave}.json`);
|
||||
if (existsSync(arquivo)) conexoes[chave] = JSON.parse(readFileSync(arquivo, "utf8"));
|
||||
const pastaConexoes = isEn ? path.join(process.cwd(), "data", "en", "conexoes") : path.join(process.cwd(), "public", "conexoes");
|
||||
const arquivo = path.join(pastaConexoes, `${chave}.json`);
|
||||
if (existsSync(arquivo)) {
|
||||
conexoes[chave] = JSON.parse(readFileSync(arquivo, "utf8"));
|
||||
} else {
|
||||
const fallback = path.join(process.cwd(), "public", "conexoes", `${chave}.json`);
|
||||
if (existsSync(fallback)) conexoes[chave] = JSON.parse(readFileSync(fallback, "utf8"));
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
Reference in new issue
Block a user