feat(i18n): Spanish localization (phase 4)
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:
1 parent
0940814522
commit
660b28c09d
72 files changed
+17848
-947
No files matched your search
@@ -3,16 +3,33 @@ import { paginaMeta, jsonLd } from "@/lib/seo";
|
||||
export async function generateMetadata({ params }) {
|
||||
const { locale } = await params;
|
||||
const isEn = locale === "en";
|
||||
const isEs = locale === "es";
|
||||
return paginaMeta({
|
||||
titulo: isEn
|
||||
titulo: isEs
|
||||
? "ESP Component Registry & IDF Component Manager · ESPDocs"
|
||||
: isEn
|
||||
? "ESP Component Registry & IDF Component Manager · ESPDocs"
|
||||
: "ESP Component Registry & IDF Component Manager · ESPDocs",
|
||||
descricao: isEn
|
||||
descricao: isEs
|
||||
? "Catálogo interactivo del ESP Component Registry: controladores de pantalla, LVGL, reconocimiento de voz ESP-SR, RainMaker, BSPs y generador de idf_component.yml."
|
||||
: isEn
|
||||
? "Official interactive catalog of the ESP Component Registry: display drivers, LVGL, ESP-SR voice recognition, RainMaker, BSPs, and idf_component.yml generator."
|
||||
: "Catálogo oficial e interativo do ESP Component Registry: drivers de displays, LVGL, reconhecimento de voz ESP-SR, RainMaker, BSPs e gerador de idf_component.yml.",
|
||||
caminho: "/componentes",
|
||||
locale,
|
||||
keywords: isEn
|
||||
keywords: isEs
|
||||
? [
|
||||
"ESP Component Registry",
|
||||
"IDF Component Manager",
|
||||
"idf_component.yml",
|
||||
"idf.py add-dependency",
|
||||
"componentes ESP32",
|
||||
"espressif esp_lvgl_port",
|
||||
"espressif esp_rainmaker",
|
||||
"espressif esp-sr",
|
||||
"bibliotecas ESP-IDF",
|
||||
]
|
||||
: isEn
|
||||
? [
|
||||
"ESP Component Registry",
|
||||
"IDF Component Manager",
|
||||
@@ -76,10 +93,30 @@ const faqsEn = [
|
||||
},
|
||||
];
|
||||
|
||||
const faqsEs = [
|
||||
{
|
||||
pergunta: "¿Qué es el ESP Component Registry y el IDF Component Manager?",
|
||||
resposta: "El ESP Component Registry (components.espressif.com) es el repositorio oficial de paquetes modulares de Espressif. El IDF Component Manager es la herramienta integrada en ESP-IDF (a partir de v4.4 y estándar en v5.x+) que descarga, compila y resuelve versiones de dependencias automáticamente desde el manifiesto idf_component.yml.",
|
||||
},
|
||||
{
|
||||
pergunta: "¿Cómo agregar un componente a mi proyecto ESP-IDF?",
|
||||
resposta: "Puede ejecutar el comando 'idf.py add-dependency \"namespace/componente^version\"' en la terminal del proyecto (por ejemplo: idf.py add-dependency \"espressif/esp_lvgl_port^2.4.0\") o editar directamente el archivo main/idf_component.yml.",
|
||||
},
|
||||
{
|
||||
pergunta: "¿Cuál es la diferencia entre usar Component Registry y submódulos git?",
|
||||
resposta: "El Component Registry elimina la complejidad de gestionar submódulos Git pesados y versiones manuales. Ofrece versionamiento semántico (^ y ~), resolución automática de dependencias transitivas y compilación modular bajo demanda.",
|
||||
},
|
||||
{
|
||||
pergunta: "¿Puedo crear y publicar mis propios componentes?",
|
||||
resposta: "Sí, cualquier desarrollador o empresa puede publicar componentes públicos o privados en el ESP Component Registry utilizando la herramienta oficial Compote CLI (pip install idf-component-manager).",
|
||||
},
|
||||
];
|
||||
|
||||
export default async function ComponentesLayout({ children, params }) {
|
||||
const { locale } = await params;
|
||||
const isEn = locale === "en";
|
||||
const faqs = isEn ? faqsEn : faqsPt;
|
||||
const isEs = locale === "es";
|
||||
const faqs = isEs ? faqsEs : isEn ? faqsEn : faqsPt;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -88,8 +125,8 @@ export default async function ComponentesLayout({ children, params }) {
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: JSON.stringify(
|
||||
jsonLd.trilha([
|
||||
{ nome: isEn ? "Home" : "Início", caminho: isEn ? "/en" : "/" },
|
||||
{ nome: "ESP Component Registry", caminho: isEn ? "/en/components" : "/componentes" },
|
||||
{ nome: isEs ? "Inicio" : isEn ? "Home" : "Início", caminho: isEs ? "/es" : isEn ? "/en" : "/" },
|
||||
{ nome: "ESP Component Registry", caminho: isEs ? "/es/componentes" : isEn ? "/en/components" : "/componentes" },
|
||||
])
|
||||
),
|
||||
}}
|
||||
@@ -105,11 +142,17 @@ export default async function ComponentesLayout({ children, params }) {
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: JSON.stringify(
|
||||
jsonLd.aplicacaoWeb({
|
||||
nome: isEn ? "ESP Component Registry Hub & Manifest Builder" : "Hub do ESP Component Registry & Construtor de Manifesto",
|
||||
descricao: isEn
|
||||
nome: isEs
|
||||
? "Hub de ESP Component Registry & Generador de Manifiesto"
|
||||
: isEn
|
||||
? "ESP Component Registry Hub & Manifest Builder"
|
||||
: "Hub do ESP Component Registry & Construtor de Manifesto",
|
||||
descricao: isEs
|
||||
? "Catálogo curado y generador de manifiesto idf_component.yml para componentes modulares de ESP-IDF."
|
||||
: isEn
|
||||
? "Curated catalog and idf_component.yml manifest generator for modular ESP-IDF components."
|
||||
: "Catálogo curado e gerador de manifesto idf_component.yml para componentes modulares do ESP-IDF.",
|
||||
caminho: isEn ? "/en/components" : "/componentes",
|
||||
caminho: isEs ? "/es/componentes" : isEn ? "/en/components" : "/componentes",
|
||||
locale,
|
||||
})
|
||||
),
|
||||
|
||||
@@ -8,6 +8,7 @@ import PageHero from "@/components/PageHero";
|
||||
import SectionHead from "@/components/SectionHead";
|
||||
import * as componentesPt from "@/lib/componentRegistryData";
|
||||
import * as componentesEn from "@/lib/data/en/componentes";
|
||||
import * as componentesEs from "@/lib/data/es/componentes";
|
||||
import {
|
||||
ArrowUpRight,
|
||||
Box,
|
||||
@@ -44,7 +45,8 @@ const ICONES_CATEGORIA = {
|
||||
export default function ComponentRegistryPage() {
|
||||
const pathname = usePathname();
|
||||
const isEn = pathname?.startsWith("/en");
|
||||
const { CATEGORIAS_COMPONENTES, COMPONENTES_REGISTRY, GUIA_COMPONENT_MANAGER } = isEn ? componentesEn : componentesPt;
|
||||
const isEs = pathname?.startsWith("/es");
|
||||
const { CATEGORIAS_COMPONENTES, COMPONENTES_REGISTRY, GUIA_COMPONENT_MANAGER } = isEs ? componentesEs : isEn ? componentesEn : componentesPt;
|
||||
|
||||
const [busca, setBusca] = useState("");
|
||||
const [categoriaAtiva, setCategoriaAtiva] = useState("todos");
|
||||
@@ -98,19 +100,23 @@ export default function ComponentRegistryPage() {
|
||||
);
|
||||
|
||||
if (selecionados.length === 0) {
|
||||
return isEn
|
||||
return isEs
|
||||
? `# No hay componentes seleccionados.\n# Haga clic en "+ Agregar al manifiesto" en las tarjetas de abajo.`
|
||||
: isEn
|
||||
? `# No components selected.\n# Click "+ Add to Manifest" on the cards below.`
|
||||
: `# Nenhum componente selecionado.\n# Clique em "+ Adicionar ao Manifesto" nos cards abaixo.`;
|
||||
}
|
||||
|
||||
let yaml = isEn
|
||||
let yaml = isEs
|
||||
? `# main/idf_component.yml\n# Generado mediante ESPDocs Component Hub (https://espdocs.cienciaembarcada.com.br/es/componentes)\n\ndependencies:\n`
|
||||
: isEn
|
||||
? `# main/idf_component.yml\n# Generated via ESPDocs Component Hub (https://espdocs.cienciaembarcada.com.br/en/components)\n\ndependencies:\n`
|
||||
: `# main/idf_component.yml\n# Gerado via ESPDocs Component Hub (https://espdocs.cienciaembarcada.com.br/componentes)\n\ndependencies:\n`;
|
||||
selecionados.forEach((c) => {
|
||||
yaml += ` ${c.namespace}/${c.name}: "${c.versao}"\n`;
|
||||
});
|
||||
return yaml;
|
||||
}, [componentesSelecionados, COMPONENTES_REGISTRY, isEn]);
|
||||
}, [componentesSelecionados, COMPONENTES_REGISTRY, isEn, isEs]);
|
||||
|
||||
const copiarManifesto = () => {
|
||||
navigator.clipboard.writeText(manifestoYaml);
|
||||
@@ -145,31 +151,34 @@ export default function ComponentRegistryPage() {
|
||||
<main id="conteudo">
|
||||
<PageHero
|
||||
isEn={isEn}
|
||||
trail={[{ label: isEn ? "Component Registry" : "Component Registry" }]}
|
||||
isEs={isEs}
|
||||
trail={[{ label: isEs ? "Component Registry" : isEn ? "Component Registry" : "Component Registry" }]}
|
||||
icon={Box}
|
||||
label="ESP-IDF Component Manager"
|
||||
title="ESP Component Registry"
|
||||
lede={
|
||||
isEn
|
||||
isEs
|
||||
? "El catálogo oficial de paquetes reutilizables de Espressif para ESP-IDF. Elija controladores, voz y pilas industriales, copie el comando y genere el manifiesto del proyecto."
|
||||
: isEn
|
||||
? "Official Espressif catalog of reusable packages for ESP-IDF. Choose drivers, voice stacks, and industrial protocols, copy commands, and generate project manifests."
|
||||
: "O catálogo oficial de pacotes reutilizáveis da Espressif para o ESP-IDF. Escolha drivers, voz e pilhas industriais, copie o comando e gere o manifesto do projeto."
|
||||
}
|
||||
>
|
||||
<a href="https://components.espressif.com" target="_blank" rel="noopener noreferrer" className="btn btn-primary">
|
||||
{isEn ? "Open official registry" : "Abrir o registro oficial"}
|
||||
{isEs ? "Abrir el registro oficial" : isEn ? "Open official registry" : "Abrir o registro oficial"}
|
||||
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
|
||||
<span className="sr-only"> {isEn ? "(opens in a new tab)" : "(abre em nova aba)"}</span>
|
||||
<span className="sr-only"> {isEs ? "(abre en una nueva pestaña)" : isEn ? "(opens in a new tab)" : "(abre em nova aba)"}</span>
|
||||
</a>
|
||||
<a href="#manifesto-builder" className="btn btn-ghost">
|
||||
{isEn ? "Generate idf_component.yml" : "Gerar idf_component.yml"}
|
||||
{isEs ? "Generar idf_component.yml" : isEn ? "Generate idf_component.yml" : "Gerar idf_component.yml"}
|
||||
</a>
|
||||
</PageHero>
|
||||
|
||||
<section className="shell pt-10 sm:pt-12" aria-label={isEn ? "Search and filters" : "Busca e filtros"}>
|
||||
<section className="shell pt-10 sm:pt-12" aria-label={isEs ? "Búsqueda y filtros" : isEn ? "Search and filters" : "Busca e filtros"}>
|
||||
<div className="panel p-5 sm:p-6">
|
||||
<div className="relative">
|
||||
<label htmlFor="busca-componente" className="sr-only">
|
||||
{isEn ? "Search by name, namespace, or tag" : "Buscar por nome, namespace ou tag"}
|
||||
{isEs ? "Buscar por nombre, namespace o etiqueta" : isEn ? "Search by name, namespace, or tag" : "Buscar por nome, namespace ou tag"}
|
||||
</label>
|
||||
<Search className="pointer-events-none absolute left-4 top-1/2 h-5 w-5 -translate-y-1/2 text-muted" aria-hidden="true" />
|
||||
<input
|
||||
@@ -177,14 +186,14 @@ export default function ComponentRegistryPage() {
|
||||
type="search"
|
||||
value={busca}
|
||||
onChange={(e) => setBusca(e.target.value)}
|
||||
placeholder={isEn ? "Search by name, namespace, or tag" : "Buscar por nome, namespace ou tag"}
|
||||
placeholder={isEs ? "Buscar por nombre, namespace o etiqueta" : isEn ? "Search by name, namespace, or tag" : "Buscar por nome, namespace ou tag"}
|
||||
autoComplete="off"
|
||||
className="field pl-12 pr-4 text-base"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-5">
|
||||
<h2 className="text-sm font-semibold text-ink">{isEn ? "Category" : "Categoria"}</h2>
|
||||
<h2 className="text-sm font-semibold text-ink">{isEs ? "Categoría" : isEn ? "Category" : "Categoria"}</h2>
|
||||
<div className="mt-3 flex flex-wrap gap-2">
|
||||
{CATEGORIAS_COMPONENTES.map((cat) => {
|
||||
const Icone = ICONES_CATEGORIA[cat.id] ?? Layers;
|
||||
@@ -192,7 +201,7 @@ export default function ComponentRegistryPage() {
|
||||
return (
|
||||
<button key={cat.id} type="button" onClick={() => setCategoriaAtiva(cat.id)} aria-pressed={categoriaAtiva === cat.id} className="chip-btn">
|
||||
<Icone className="h-4 w-4" aria-hidden="true" />
|
||||
{cat.id === "todos" ? (isEn ? "All" : "Todos") : cat.nome.replace(/\s*\(.*\)/, "").split(",")[0].split(" &")[0]}
|
||||
{cat.id === "todos" ? (isEs ? "Todos" : isEn ? "All" : "Todos") : cat.nome.replace(/\s*\(.*\)/, "").split(",")[0].split(" &")[0]}
|
||||
<span className="tabular-nums opacity-80">{contagem}</span>
|
||||
</button>
|
||||
);
|
||||
@@ -201,11 +210,11 @@ export default function ComponentRegistryPage() {
|
||||
</div>
|
||||
|
||||
<div className="mt-5 border-t border-line pt-5">
|
||||
<h2 className="text-sm font-semibold text-ink">{isEn ? "Compatible chip" : "Chip compatível"}</h2>
|
||||
<h2 className="text-sm font-semibold text-ink">{isEs ? "Chip compatible" : isEn ? "Compatible chip" : "Chip compatível"}</h2>
|
||||
<div className="mt-3 flex flex-wrap gap-2">
|
||||
{chipsDisponiveis.map((chip) => (
|
||||
<button key={chip} type="button" onClick={() => setChipFiltro(chip)} aria-pressed={chipFiltro === chip} className="chip-btn">
|
||||
{chip === "todos" ? (isEn ? "All" : "Todos") : chip}
|
||||
{chip === "todos" ? (isEs ? "Todos" : isEn ? "All" : "Todos") : chip}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
@@ -216,17 +225,17 @@ export default function ComponentRegistryPage() {
|
||||
<section className="shell section pt-8 sm:pt-10" aria-labelledby="lista-titulo">
|
||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||
<h2 id="lista-titulo" role="status" aria-live="polite" className="text-base font-semibold text-ink">
|
||||
{componentesFiltrados.length} {componentesFiltrados.length === 1 ? (isEn ? "component" : "componente") : (isEn ? "components" : "componentes")}
|
||||
{componentesFiltrados.length} {componentesFiltrados.length === 1 ? (isEs ? "componente" : isEn ? "component" : "componente") : (isEs ? "componentes" : isEn ? "components" : "componentes")}
|
||||
</h2>
|
||||
<div className="flex flex-wrap items-center gap-x-5 gap-y-1">
|
||||
{totalFiltros > 0 && (
|
||||
<button type="button" onClick={limparFiltros} className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong">
|
||||
<X className="h-4 w-4" aria-hidden="true" />
|
||||
{isEn ? "Clear filters" : "Limpar filtros"}
|
||||
{isEs ? "Limpiar filtros" : isEn ? "Clear filters" : "Limpar filtros"}
|
||||
</button>
|
||||
)}
|
||||
<a href="#manifesto-builder" className="inline-flex min-h-11 items-center gap-1.5 text-sm font-medium text-accent hover:text-accent-strong">
|
||||
{isEn ? "Manifest:" : "Manifesto:"} {componentesSelecionados.length} {componentesSelecionados.length === 1 ? (isEn ? "component" : "componente") : (isEn ? "components" : "componentes")}
|
||||
{isEs ? "Manifiesto:" : isEn ? "Manifest:" : "Manifesto:"} {componentesSelecionados.length} {componentesSelecionados.length === 1 ? (isEs ? "componente" : isEn ? "component" : "componente") : (isEs ? "componentes" : isEn ? "components" : "componentes")}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -235,13 +244,17 @@ export default function ComponentRegistryPage() {
|
||||
<div className="card mt-6 px-6 py-14 text-center">
|
||||
<Box className="mx-auto h-10 w-10 text-muted" aria-hidden="true" />
|
||||
<h3 className="mt-4 font-display text-xl font-semibold text-ink">
|
||||
{isEn ? "No components found" : "Nenhum componente encontrado"}
|
||||
{isEs ? "No se encontraron componentes" : isEn ? "No components found" : "Nenhum componente encontrado"}
|
||||
</h3>
|
||||
<p className="mx-auto mt-2 max-w-md text-sm text-muted">
|
||||
{isEn ? "Search for a more general term or return to all categories." : "Busque por um termo mais geral ou volte para todas as categorias."}
|
||||
{isEs
|
||||
? "Busque por un término más general o regrese a todas las categorías."
|
||||
: isEn
|
||||
? "Search for a more general term or return to all categories."
|
||||
: "Busque por um termo mais geral ou volte para todas as categorias."}
|
||||
</p>
|
||||
<button type="button" onClick={limparFiltros} className="btn btn-primary mt-6">
|
||||
{isEn ? "Clear filters" : "Limpar filtros"}
|
||||
{isEs ? "Limpiar filtros" : isEn ? "Clear filters" : "Limpar filtros"}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
@@ -261,7 +274,7 @@ export default function ComponentRegistryPage() {
|
||||
{comp.oficial && (
|
||||
<span className="chip chip-accent px-2 py-0">
|
||||
<ShieldCheck className="h-3 w-3" aria-hidden="true" />
|
||||
{isEn ? "Official" : "Oficial"}
|
||||
{isEs ? "Oficial" : isEn ? "Official" : "Oficial"}
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
@@ -285,12 +298,12 @@ export default function ComponentRegistryPage() {
|
||||
type="button"
|
||||
onClick={() => copiarComando(comp.id, cliCmd)}
|
||||
className="code-panel flex w-full min-h-11 items-center justify-between gap-3 rounded-lg px-3 py-2 text-left font-mono text-xs transition-colors hover:border-white/30"
|
||||
aria-label={isEn ? `Copy command to add ${comp.name}` : `Copiar comando para adicionar ${comp.name}`}
|
||||
aria-label={isEs ? `Copiar comando para agregar ${comp.name}` : isEn ? `Copy command to add ${comp.name}` : `Copiar comando para adicionar ${comp.name}`}
|
||||
>
|
||||
<span className="truncate text-[#e9eef4]">{cliCmd}</span>
|
||||
{foiCopiado ? <Check className="h-4 w-4 shrink-0 text-[#5fe0a2]" aria-hidden="true" /> : <Copy className="h-4 w-4 shrink-0 text-[#a6afbd]" aria-hidden="true" />}
|
||||
</button>
|
||||
<p role="status" className="sr-only">{foiCopiado ? (isEn ? "Command copied" : "Comando copiado") : ""}</p>
|
||||
<p role="status" className="sr-only">{foiCopiado ? (isEs ? "Comando copiado" : isEn ? "Command copied" : "Comando copiado") : ""}</p>
|
||||
|
||||
<p className="mt-3 text-xs text-muted">
|
||||
<span className="font-medium text-ink-soft">Chips: </span>
|
||||
@@ -306,14 +319,14 @@ export default function ComponentRegistryPage() {
|
||||
className={`btn btn-sm ${selecionado ? "btn-primary" : "btn-ghost"}`}
|
||||
>
|
||||
{selecionado ? <Check className="h-4 w-4" aria-hidden="true" /> : <Plus className="h-4 w-4" aria-hidden="true" />}
|
||||
{selecionado ? (isEn ? "In manifest" : "No manifesto") : (isEn ? "Add to manifest" : "Adicionar ao manifesto")}
|
||||
{selecionado ? (isEs ? "En manifiesto" : isEn ? "In manifest" : "No manifesto") : (isEs ? "Agregar al manifiesto" : isEn ? "Add to manifest" : "Adicionar ao manifesto")}
|
||||
</button>
|
||||
<a
|
||||
href={comp.urlRegistry}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="btn-icon inline-flex h-11 w-11 items-center justify-center rounded-full text-muted transition-colors hover:bg-surface-2 hover:text-accent"
|
||||
aria-label={isEn ? `Open ${comp.name} in official registry (new tab)` : `Abrir ${comp.name} no registro oficial (nova aba)`}
|
||||
aria-label={isEs ? `Abrir ${comp.name} en el registro oficial (nueva pestaña)` : isEn ? `Open ${comp.name} in official registry (new tab)` : `Abrir ${comp.name} no registro oficial (nova aba)`}
|
||||
>
|
||||
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
|
||||
</a>
|
||||
@@ -329,12 +342,14 @@ export default function ComponentRegistryPage() {
|
||||
<div className="panel p-6 sm:p-9">
|
||||
<div className="flex flex-col justify-between gap-5 md:flex-row md:items-end">
|
||||
<div className="max-w-2xl">
|
||||
<p className="eyebrow">{isEn ? "Manifest generator" : "Gerador de manifesto"}</p>
|
||||
<p className="eyebrow">{isEs ? "Generador de manifiesto" : isEn ? "Manifest generator" : "Gerador de manifesto"}</p>
|
||||
<h2 id="manifesto-titulo" className="section-title mt-3">
|
||||
{isEn ? "Your idf_component.yml" : "Seu idf_component.yml"}
|
||||
{isEs ? "Su idf_component.yml" : isEn ? "Your idf_component.yml" : "Seu idf_component.yml"}
|
||||
</h2>
|
||||
<p className="mt-3 text-sm leading-relaxed text-muted">
|
||||
{isEn ? (
|
||||
{isEs ? (
|
||||
<>Guarde el archivo en la carpeta <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono">main/</code> del proyecto y ESP-IDF descargará todas las bibliotecas durante la compilación.</>
|
||||
) : isEn ? (
|
||||
<>Save this file in your project's <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono">main/</code> folder and ESP-IDF will download all dependencies during build.</>
|
||||
) : (
|
||||
<>Salve o arquivo na pasta <code className="rounded bg-surface-2 px-1.5 py-0.5 font-mono">main/</code> do projeto e o ESP-IDF baixa todas as bibliotecas na compilação.</>
|
||||
@@ -344,27 +359,27 @@ export default function ComponentRegistryPage() {
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<button type="button" onClick={copiarManifesto} className="btn btn-primary btn-sm">
|
||||
{manifestoCopiado ? <Check className="h-4 w-4" aria-hidden="true" /> : <Copy className="h-4 w-4" aria-hidden="true" />}
|
||||
<span role="status">{manifestoCopiado ? (isEn ? "Copied" : "Copiado") : (isEn ? "Copy YAML" : "Copiar YAML")}</span>
|
||||
<span role="status">{manifestoCopiado ? (isEs ? "Copiado" : isEn ? "Copied" : "Copiado") : (isEs ? "Copiar YAML" : isEn ? "Copy YAML" : "Copiar YAML")}</span>
|
||||
</button>
|
||||
<button type="button" onClick={baixarManifesto} className="btn btn-ghost btn-sm">
|
||||
<Download className="h-4 w-4" aria-hidden="true" />
|
||||
{isEn ? "Download .yml" : "Baixar .yml"}
|
||||
{isEs ? "Descargar .yml" : isEn ? "Download .yml" : "Baixar .yml"}
|
||||
</button>
|
||||
{componentesSelecionados.length > 0 && (
|
||||
<button type="button" onClick={() => setComponentesSelecionados([])} className="btn btn-ghost btn-sm">
|
||||
<Trash2 className="h-4 w-4" aria-hidden="true" />
|
||||
{isEn ? "Clear" : "Limpar"}
|
||||
{isEs ? "Limpiar" : isEn ? "Clear" : "Limpar"}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="code-panel mt-6">
|
||||
<pre tabIndex={0} aria-label={isEn ? "Content of idf_component.yml" : "Conteúdo do idf_component.yml"} className="!text-sm"><code className="text-[#e9eef4]">{manifestoYaml}</code></pre>
|
||||
<pre tabIndex={0} aria-label={isEs ? "Contenido de idf_component.yml" : isEn ? "Content of idf_component.yml" : "Conteúdo do idf_component.yml"} className="!text-sm"><code className="text-[#e9eef4]">{manifestoYaml}</code></pre>
|
||||
</div>
|
||||
|
||||
{componentesSelecionados.length > 0 && (
|
||||
<ul className="mt-5 flex flex-wrap items-center gap-2" aria-label={isEn ? "Included components" : "Componentes incluídos"}>
|
||||
<ul className="mt-5 flex flex-wrap items-center gap-2" aria-label={isEs ? "Componentes incluidos" : isEn ? "Included components" : "Componentes incluídos"}>
|
||||
{componentesSelecionados.map((id) => {
|
||||
const c = COMPONENTES_REGISTRY.find((item) => item.id === id);
|
||||
if (!c) return null;
|
||||
@@ -375,7 +390,7 @@ export default function ComponentRegistryPage() {
|
||||
type="button"
|
||||
onClick={() => toggleSelecaoManifesto(id)}
|
||||
className="-my-2 grid h-11 w-11 place-items-center rounded-full hover:bg-accent/15"
|
||||
aria-label={isEn ? `Remove ${c.name} from manifest` : `Remover ${c.name} do manifesto`}
|
||||
aria-label={isEs ? `Eliminar ${c.name} del manifiesto` : isEn ? `Remove ${c.name} from manifest` : `Remover ${c.name} do manifesto`}
|
||||
>
|
||||
<X className="h-3.5 w-3.5" aria-hidden="true" />
|
||||
</button>
|
||||
@@ -388,7 +403,7 @@ export default function ComponentRegistryPage() {
|
||||
</section>
|
||||
|
||||
<section className="shell section border-t border-line pt-14" aria-labelledby="guia-titulo">
|
||||
<SectionHead id="guia-titulo" eyebrow={isEn ? "Quick guide" : "Guia rápido"} title={GUIA_COMPONENT_MANAGER.titulo} lede={GUIA_COMPONENT_MANAGER.resumo} />
|
||||
<SectionHead id="guia-titulo" eyebrow={isEs ? "Guía rápida" : isEn ? "Quick guide" : "Guia rápido"} title={GUIA_COMPONENT_MANAGER.titulo} lede={GUIA_COMPONENT_MANAGER.resumo} />
|
||||
|
||||
<ul className="mt-8 grid gap-3 md:grid-cols-2 lg:grid-cols-4">
|
||||
{GUIA_COMPONENT_MANAGER.vantagens.map((v) => (
|
||||
@@ -401,7 +416,7 @@ export default function ComponentRegistryPage() {
|
||||
|
||||
<h3 className="mt-12 flex items-center gap-2 font-display text-xl font-semibold tracking-[-0.03em] text-ink">
|
||||
<Terminal className="h-5 w-5 text-accent" aria-hidden="true" />
|
||||
{isEn ? "Essential commands" : "Comandos essenciais"}
|
||||
{isEs ? "Comandos esenciales" : isEn ? "Essential commands" : "Comandos essenciais"}
|
||||
</h3>
|
||||
<ul className="mt-4 space-y-3">
|
||||
{GUIA_COMPONENT_MANAGER.comandosCli.map((cmd, i) => (
|
||||
@@ -416,7 +431,7 @@ export default function ComponentRegistryPage() {
|
||||
className="inline-flex min-h-11 shrink-0 items-center gap-1.5 self-start rounded-full border border-white/15 px-4 text-sm font-medium text-[#e9eef4] transition-colors hover:bg-white/10 md:self-auto"
|
||||
>
|
||||
{copiadoId === `cmd-${i}` ? <Check className="h-4 w-4 text-[#5fe0a2]" aria-hidden="true" /> : <Copy className="h-4 w-4" aria-hidden="true" />}
|
||||
{copiadoId === `cmd-${i}` ? (isEn ? "Copied" : "Copiado") : (isEn ? "Copy" : "Copiar")}
|
||||
{copiadoId === `cmd-${i}` ? (isEs ? "Copiado" : isEn ? "Copied" : "Copiado") : (isEs ? "Copiar" : isEn ? "Copy" : "Copiar")}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
@@ -425,10 +440,17 @@ export default function ComponentRegistryPage() {
|
||||
<div className="callout mt-8">
|
||||
<h3 className="flex items-center gap-2 font-semibold text-ink">
|
||||
<HelpCircle className="h-4 w-4 text-accent" aria-hidden="true" />
|
||||
{isEn ? "Semantic versioning in ESP-IDF" : "Versionamento semântico no ESP-IDF"}
|
||||
{isEs ? "Versionamiento semántico en ESP-IDF" : isEn ? "Semantic versioning in ESP-IDF" : "Versionamento semântico no ESP-IDF"}
|
||||
</h3>
|
||||
<ul className="mt-2 list-disc space-y-1.5 pl-5">
|
||||
{isEn ? (
|
||||
{isEs ? (
|
||||
<>
|
||||
<li><code>^1.2.0</code>: acepta actualizaciones menores y correcciones (1.2.1, 1.3.0), pero bloquea cambios importantes de API (2.0.0). <strong>Recomendado.</strong></li>
|
||||
<li><code>~1.2.0</code>: acepta solo correcciones de errores (1.2.1, 1.2.5).</li>
|
||||
<li><code>1.2.0</code>: bloquea en esta versión exacta.</li>
|
||||
<li><code>*</code>: acepta cualquier versión. Evite en producción.</li>
|
||||
</>
|
||||
) : isEn ? (
|
||||
<>
|
||||
<li><code>^1.2.0</code>: accepts minor updates and bug fixes (1.2.1, 1.3.0), but blocks breaking API changes (2.0.0). <strong>Recommended.</strong></li>
|
||||
<li><code>~1.2.0</code>: accepts patch releases only (1.2.1, 1.2.5).</li>
|
||||
|
||||
Reference in new issue
Block a user