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

+5 -5
View File
@@ -278,7 +278,7 @@ export const COMPONENTES_REGISTRY = [
categoria: "cloud_conectividade",
oficial: true,
popular: true,
titulo: "ESP-NOW Enhanced & Provisioning",
titulo: "ESP-NOW 增强版与配网",
descricao: "ESP-NOW 协议的扩展,提供遥控配对、AES-128 安全以及多设备控制等高级功能。",
tags: ["ESP-NOW", "无线", "低延迟", "广播", "遥控"],
chips: ["ESP32", "ESP32-S2", "ESP32-S3", "ESP32-C3", "ESP32-C6"],
@@ -406,7 +406,7 @@ export const COMPONENTES_REGISTRY = [
oficial: true,
popular: true,
titulo: "ESP Matter SDK",
descricao: "官方 SDK,用于创建可在 Wi-Fi 和 Thread 上与 Apple Home、Google Home、Amazon Alexa 和 Home Assistant 互操作的设备。",
descricao: "官方 SDK,用于创建可在 Wi-Fi 和 Thread 上与 Apple Home、Google Home、Alexa 和 Home Assistant 互操作的设备。",
tags: ["Matter", "智能家居", "Apple HomeKit", "Google Home", "Thread", "CHIP"],
chips: ["ESP32", "ESP32-S3", "ESP32-C3", "ESP32-C6", "ESP32-H2"],
urlRegistry: "https://components.espressif.com/components/espressif/esp-matter",
@@ -494,7 +494,7 @@ export const COMPONENTES_REGISTRY = [
categoria: "drivers_perifericos",
oficial: true,
popular: true,
titulo: "Addressable LED Strip (WS2812/SK6812)",
titulo: "可寻址 LED 灯带(WS2812/SK6812)",
descricao: "高性能驱动,使用 RMT 或 SPI 外设控制 WS2812、WS2813 和 SK6812 可寻址 LED 灯带与灯阵。",
tags: ["WS2812B", "Neopixel", "SK6812", "RMT", "LED 灯带", "RGB"],
chips: ["ESP32", "ESP32-S2", "ESP32-S3", "ESP32-C3", "ESP32-C6", "ESP32-P4"],
@@ -719,7 +719,7 @@ export const COMPONENTES_REGISTRY = [
categoria: "bsp_placas",
oficial: false,
popular: true,
titulo: "BSP Waveshare ESP32-P4 Touch LCD 7\"",
titulo: "BSP Waveshare ESP32-P4 7\" 触摸 LCD",
descricao: "面向高性能 Waveshare ESP32-P4 开发板的支持包,配备 7 英寸电容触摸屏(MIPI-DSI 1024x600)和 Wi-Fi 6 协处理器。",
tags: ["BSP", "ESP32-P4", "MIPI-DSI", "Waveshare", "7 英寸屏", "触摸"],
chips: ["ESP32-P4"],
@@ -757,7 +757,7 @@ export const COMPONENTES_REGISTRY = [
categoria: "sistema_utilitarios",
oficial: true,
popular: true,
titulo: "ESP-IDF C++ Idiomatic Wrappers",
titulo: "ESP-IDF C++ 现代封装",
descricao: "现代 C++(C++17/C++20/C++23)类与封装集合,采用 RAII 语义,覆盖 GPIO、Wi-Fi、定时器、FreeRTOS 队列和信号量。",
tags: ["C++", "C++20", "RAII", "Modern C++", "面向对象", "FreeRTOS"],
chips: ["ESP32", "ESP32-S2", "ESP32-S3", "ESP32-C3", "ESP32-C6", "ESP32-H2", "ESP32-P4"],
+184
View File
@@ -0,0 +1,184 @@
/**
* Conhecimento de domínio da busca inteligente (zh-CN).
*
* Sem dependências nem alias de import: roda no servidor (montando o índice),
* no navegador (interpretando a consulta) e em scripts de teste no Node.
*
* Todos os textos de `termos` já estão normalizados (minúsculos, sem acento).
*/
export const normalizar = (s = "") =>
String(s)
.toLowerCase()
.normalize("NFD")
.replace(/[\u0300-\u036f]/g, "");
/**
* Reconhece pinos ocupados por flash/PSRAM com base no que o diagrama diz.
* "forte": o pino é consumido pela memória (ou é a alimentação dela).
* "fraco": só é afetado em certos modos (ex.: SPI de 8 linhas/octal).
* Avisos genéricos de tensão mínima ("para chips com flash integrada...") não contam.
*/
const nivelMemoria = (palavra) => (p) => {
const citam = p._avs.filter((a) => a.includes(palavra) && !/^对于集成/.test(a));
if (citam.some((a) => /(存储使用|专用于|连接到|用于存储)/.test(a) && !/除非/.test(a))) return "forte";
if (p._fn.some((f) => /(供电|alimentacao|vdd)/.test(f) && f.includes(palavra))) return "forte";
if (citam.length) return "fraco";
return null;
};
/**
* Assuntos que o usuário pode citar. Cada um sabe:
* - termos: como as pessoas escrevem (sinônimos, siglas, plurais comuns);
* - pinoCats / pinoRe: como reconhecer os pinos relacionados no diagrama;
* - pinoRotulo: frase usada no título do resultado de pinos.
* Os dados de especificação ligam-se aos assuntos por SPEC_CAMPOS.
*/
export const TOPICOS = [
{ id: "flash", nome: "闪存", termos: ["flash", "memoria flash", "spi flash", "armazenamento", "firmware", "rom externa", "闪存", "外部闪存", "程序存储", "固件存储"], pinoNivel: nivelMemoria("flash"), pinoRotulo: "连接到闪存" },
{ id: "psram", nome: "PSRAM", termos: ["psram", "ram externa", "spiram", "外部内存", "伪静态"], pinoNivel: nivelMemoria("psram"), pinoRotulo: "连接到 PSRAM" },
{ id: "memoria", nome: "内存", termos: ["memoria", "sram", "heap", "rtc ram", "kb de ram", "memoria interna", "ram", "memory", "内存", "内部内存", "堆", "存储器", "容量"], pinoRotulo: "" },
{ id: "wifi", nome: "Wi-Fi", termos: ["wifi", "wi-fi", "wireless", "sem fio", "802.11", "wifi6", "wifi 6", "wi-fi 6", "无线网", "无线", "无线网络"], pinoCats: ["Antena"], pinoRotulo: "天线与射频" },
{ id: "bluetooth", nome: "蓝牙", termos: ["bluetooth", "ble", "bt", "bluetooth le", "mesh", "蓝牙", "低功耗蓝牙", "经典蓝牙"], pinoCats: ["Antena"], pinoRotulo: "天线与射频" },
{ id: "zigbee", nome: "Zigbee/Thread", termos: ["zigbee", "thread", "802.15.4", "ieee 802.15.4", "组网"], pinoRotulo: "" },
{ id: "matter", nome: "Matter", termos: ["matter", "casa inteligente", "smart home", "智能家居", "家居"], pinoRotulo: "" },
{ id: "ethernet", nome: "以太网", termos: ["ethernet", "rmii", "cabo de rede", "lan", "以太网", "网口", "有线网络", "网线"], pinoCats: ["Ethernet"], pinoRotulo: "以太网" },
{ id: "can", nome: "CAN / TWAI", termos: ["can", "twai", "can bus", "canbus", "can fd", "总线", "车载总线"], pinoRe: /twai|\bcan\b/, pinoRotulo: "CAN/TWAI" },
{ id: "usb", nome: "USB", termos: ["usb", "otg", "usb serial", "usb otg", "hid", "cdc", "原生usb"], pinoCats: ["USB"], pinoRotulo: "USB" },
{ id: "jtag", nome: "JTAG / 调试", termos: ["jtag", "debug", "depuracao", "depurar", "openocd", "gdb", "调试", "调试器", "断点"], pinoCats: ["JTAG"], pinoRotulo: "JTAG" },
{ id: "adc", nome: "ADC", termos: ["adc", "analogico", "entrada analogica", "conversor analogico", "analogread", "saradc", "analog", "模数转换", "模拟输入", "模拟量", "模拟"], pinoCats: ["ADC"], pinoRotulo: "带 ADC 功能" },
{ id: "dac", nome: "DAC", termos: ["dac", "saida analogica", "conversor digital", "数模转换", "模拟输出"], pinoCats: ["DAC"], pinoRotulo: "带 DAC 功能" },
{ id: "touch", nome: "电容触摸", termos: ["touch", "capacitivo", "toque", "touchpad", "sensor de toque", "触摸", "触控", "电容"], pinoCats: ["Touch"], pinoRotulo: "电容触摸" },
{ id: "uart", nome: "UART", termos: ["uart", "serial", "tx", "rx", "txd", "rxd", "porta serial", "串口", "串行", "串行通信"], pinoCats: ["UART"], pinoRotulo: "UART" },
{ id: "spi", nome: "SPI", termos: ["spi", "mosi", "miso", "sclk", "barramento spi", "spi总线"], pinoCats: ["SPI"], pinoRotulo: "SPI" },
{ id: "i2c", nome: "I2C", termos: ["i2c", "sda", "scl", "twi", "iic", "i2c总线"], pinoCats: ["I2C"], pinoRotulo: "I2C" },
{ id: "i2s", nome: "I2S", termos: ["i2s", "audio", "som", "microfone", "pdm", "codec", "音频", "声音", "麦克风", "编解码"], pinoRe: /i2s|\bpdm\b/, pinoRotulo: "I2S / 音频" },
{ id: "pwm", nome: "PWM", termos: ["pwm", "ledc", "mcpwm", "servo", "dimmer", "脉宽", "舵机", "调光", "电机"], pinoRe: /ledc|pwm/, pinoRotulo: "PWM" },
{ id: "sd", nome: "SD 卡 / SDIO", termos: ["sd", "sdio", "sd card", "sdcard", "cartao sd", "microsd", "sdmmc", "mmc", "sd卡", "存储卡", "内存卡"], pinoCats: ["SD"], pinoRe: /sdio|sdmmc|\bsd\b/, pinoRotulo: "SD 卡 / SDIO" },
{ id: "camera", nome: "摄像头", termos: ["camera", "cam", "dvp", "csi", "mipi csi", "ov2640", "video", "摄像头", "相机", "视频", "拍照"], pinoCats: ["CSI"], pinoRe: /\bcam\b|dvp|cam_/, pinoRotulo: "摄像头" },
{ id: "lcd", nome: "显示屏 / LCD", termos: ["lcd", "display", "tela", "dsi", "mipi dsi", "oled", "tft", "lvgl", "rgb", "显示屏", "屏幕", "液晶", "显示"], pinoCats: ["DSI"], pinoRe: /lcd/, pinoRotulo: "显示屏/LCD" },
{ id: "strapping", nome: "启动配置", termos: ["strapping", "boot", "bootstrap", "modo de boot", "download mode", "modo de gravacao", "inicializacao", "启动配置", "启动模式", "下载模式", "烧录模式"], pinoCats: ["Strapping"], pinoRotulo: "启动配置" },
{ id: "energia_pinos", nome: "电源", termos: ["alimentacao", "vdd", "3v3", "3.3v", "tensao", "regulador", "ldo", "fonte", "power", "电源", "供电", "电压", "稳压", "稳压器"], pinoCats: ["Power"], pinoRotulo: "电源" },
{ id: "clock", nome: "时钟 / 晶振", termos: ["clock", "xtal", "cristal", "oscilador", "32khz", "40mhz", "crystal", "时钟", "晶振", "晶体", "振荡器"], pinoCats: ["Clock"], pinoRotulo: "时钟/晶振" },
{ id: "gpio", nome: "GPIO", termos: ["gpio", "entradas e saidas", "通用io", "输入输出"], pinoCats: ["GPIO"], pinoRotulo: "GPIO" },
{ id: "baixo_consumo", nome: "低功耗 / ULP", termos: ["ulp", "lp core", "lp cpu", "coprocessador", "lp gpio", "low power", "rtc gpio", "协处理器", "超低功耗"], pinoCats: ["Low Power"], pinoRotulo: "低功耗(LP/RTC)" },
{ id: "antena", nome: "天线 / 射频", termos: ["antena", "rf", "radiofrequencia", "ipex", "antenna", "天线", "射频"], pinoCats: ["Antena"], pinoRotulo: "天线/射频" },
{ id: "seguranca", nome: "安全", termos: ["seguranca", "secure boot", "criptografia", "encriptacao", "aes", "sha", "rsa", "hmac", "ecdsa", "efuse", "tee", "trng", "rng", "hsm", "protecao", "security", "安全", "加密", "安全启动", "密钥", "熔丝", "可信"], pinoRotulo: "" },
{ id: "consumo", nome: "功耗", termos: ["consumo", "bateria", "deep sleep", "light sleep", "sleep", "modem sleep", "corrente", "miliamperes", "autonomia", "economia de energia", "low power mode", "power consumption", "功耗", "电池", "深度睡眠", "浅睡眠", "电流", "待机", "续航", "省电", "耗电"], pinoRotulo: "" },
{ id: "temperatura", nome: "温度", termos: ["temperatura", "calor", "graus", "faixa de temperatura", "industrial", "temperature", "温度", "工作温度", "高温", "低温"], pinoRotulo: "" },
{ id: "ia", nome: "AI / 加速", termos: ["ia", "ai", "machine learning", "ml", "tinyml", "vetorial", "inteligencia artificial", "rede neural", "esp-nn", "esp-dl", "人工智能", "机器学习", "神经网络", "边缘ai", "向量"], pinoRotulo: "" },
{ id: "processador", nome: "处理器", termos: ["processador", "cpu", "nucleo", "nucleos", "core", "dual core", "single core", "arquitetura", "xtensa", "risc-v", "riscv", "processor", "处理器", "内核", "核心", "双核", "单核", "架构", "主频"], pinoRotulo: "" },
{ id: "frequencia", nome: "频率", termos: ["frequencia", "mhz", "velocidade", "desempenho", "performance", "frequency", "频率", "主频", "速度", "性能"], pinoRotulo: "" },
{ id: "ferramentas", nome: "工具 / SDK", termos: ["esp-idf", "idf", "arduino", "sdk", "toolchain", "versao do idf", "tools", "开发环境", "工具链", "开发框架"], pinoRotulo: "" },
{ id: "encapsulamento", nome: "模组与封装", termos: ["modulo", "modulos", "encapsulamento", "package", "qfn", "wroom", "wrover", "mini-1", "modules", "模组", "封装", "型号"], pinoRotulo: "" },
];
/**
* Campos de public/series.json que respondem a cada assunto.
* `campo` aceita caminho com ponto (seguranca.aes). `secao` é o id da âncora
* na página /series/[key].
*/
export const SPEC_CAMPOS = [
{ campo: "arquitetura", label: "架构", secao: "processador", topicos: ["processador"] },
{ campo: "nucleos", label: "内核", secao: "processador", topicos: ["processador"] },
{ campo: "frequencia", label: "频率", secao: "processador", topicos: ["frequencia", "processador"] },
{ campo: "coprocessador_ulp", label: "ULP 协处理器", secao: "processador", topicos: ["baixo_consumo"] },
{ campo: "aceleradores_ia", label: "AI 加速器", secao: "processador", topicos: ["ia"] },
{ campo: "wifi", label: "Wi-Fi", secao: "conectividade", topicos: ["wifi"] },
{ campo: "bluetooth", label: "蓝牙", secao: "conectividade", topicos: ["bluetooth"] },
{ campo: "zigbee_thread", label: "Zigbee/Thread", secao: "conectividade", topicos: ["zigbee"] },
{ campo: "matter", label: "Matter", secao: "conectividade", topicos: ["matter"] },
{ campo: "ethernet", label: "以太网", secao: "conectividade", topicos: ["ethernet"] },
{ campo: "ethernet_mac", label: "以太网 MAC", secao: "conectividade", topicos: ["ethernet"] },
{ campo: "can", label: "CAN", secao: "conectividade", topicos: ["can"] },
{ campo: "memoria_sram", label: "SRAM", secao: "memoria", topicos: ["memoria"] },
{ campo: "memoria_sram_rtc", label: "RTC SRAM", secao: "memoria", topicos: ["memoria", "baixo_consumo"] },
{ campo: "memoria_rom", label: "ROM", secao: "memoria", topicos: ["memoria"] },
{ campo: "flash_externa", label: "外部闪存", secao: "memoria", topicos: ["flash", "memoria"] },
{ campo: "psram_externa", label: "外部 PSRAM", secao: "memoria", topicos: ["psram", "memoria"] },
{ campo: "gpio", label: "GPIO", secao: "perifericos", topicos: ["gpio"] },
{ campo: "adc", label: "ADC", secao: "perifericos", topicos: ["adc"] },
{ campo: "dac", label: "DAC", secao: "perifericos", topicos: ["dac"] },
{ campo: "touch", label: "触摸", secao: "perifericos", topicos: ["touch"] },
{ campo: "uart", label: "UART", secao: "perifericos", topicos: ["uart"] },
{ campo: "spi", label: "SPI", secao: "perifericos", topicos: ["spi", "flash"] },
{ campo: "i2c", label: "I2C", secao: "perifericos", topicos: ["i2c"] },
{ campo: "i2s", label: "I2S", secao: "perifericos", topicos: ["i2s"] },
{ campo: "pwm", label: "PWM", secao: "perifericos", topicos: ["pwm"] },
{ campo: "usb", label: "USB", secao: "perifericos", topicos: ["usb"] },
{ campo: "lcd", label: "LCD", secao: "interfaces", topicos: ["lcd"] },
{ campo: "camera", label: "摄像头", secao: "interfaces", topicos: ["camera"] },
{ campo: "mipi_csi", label: "MIPI CSI", secao: "interfaces", topicos: ["camera"] },
{ campo: "mipi_dsi", label: "MIPI DSI", secao: "interfaces", topicos: ["lcd"] },
{ campo: "sdio", label: "SDIO", secao: "interfaces", topicos: ["sd"] },
{ campo: "sensor_temperatura", label: "温度传感器", secao: "interfaces", topicos: ["temperatura"] },
{ campo: "seguranca.aes", label: "AES", secao: "seguranca", topicos: ["seguranca"] },
{ campo: "seguranca.sha", label: "SHA", secao: "seguranca", topicos: ["seguranca"] },
{ campo: "seguranca.rsa", label: "RSA", secao: "seguranca", topicos: ["seguranca"] },
{ campo: "seguranca.ecc", label: "ECC", secao: "seguranca", topicos: ["seguranca"] },
{ campo: "seguranca.ecdsa", label: "ECDSA", secao: "seguranca", topicos: ["seguranca"] },
{ campo: "seguranca.hmac", label: "HMAC", secao: "seguranca", topicos: ["seguranca"] },
{ campo: "seguranca.assinatura_digital", label: "数字签名", secao: "seguranca", topicos: ["seguranca"] },
{ campo: "seguranca.rng", label: "随机数发生器", secao: "seguranca", topicos: ["seguranca"] },
{ campo: "seguranca.criptografia_flash", label: "闪存加密", secao: "seguranca", topicos: ["seguranca", "flash"] },
{ campo: "seguranca.secure_boot", label: "安全启动", secao: "seguranca", topicos: ["seguranca", "strapping"] },
{ campo: "temperatura_operacao", label: "工作温度", secao: "temperatura", topicos: ["temperatura"] },
{ campo: "temperatura_armazenamento", label: "存储温度", secao: "temperatura", topicos: ["temperatura"] },
{ campo: "esp_idf_minimo", label: "最低 ESP-IDF 版本", secao: "ferramentas", topicos: ["ferramentas"] },
{ campo: "arduino_core", label: "Arduino 核心", secao: "ferramentas", topicos: ["ferramentas"] },
{ campo: "depuracao", label: "调试", secao: "ferramentas", topicos: ["jtag", "ferramentas"] },
{ campo: "encapsulamento", label: "封装", secao: "ferramentas", topicos: ["encapsulamento"] },
{ campo: "modulos", label: "模组", secao: "ferramentas", topicos: ["encapsulamento"] },
];
const ROTULOS_ENERGIA = {
active: "工作",
modem_sleep: "Modem Sleep",
light_sleep: "Light Sleep",
deep_sleep: "Deep Sleep",
hibernation: "Hibernation",
};
const pegar = (obj, caminho) => caminho.split(".").reduce((o, k) => (o == null ? o : o[k]), obj);
/**
* Monta, para cada série, a lista plana de especificações (com os assuntos a
* que respondem) e os pinos do diagrama. É o que o navegador baixa.
*
* @param {Record<string, object>} series conteúdo de public/series.json
* @param {Record<string, object[]>} conexoes pinos por série (public/conexoes)
*/
export function montarConhecimento(series, conexoes) {
const saida = {};
for (const [chave, s] of Object.entries(series)) {
const specs = [];
for (const c of SPEC_CAMPOS) {
const valor = pegar(s, c.campo);
if (valor == null || valor === "") continue;
specs.push({ label: c.label, valor: String(valor), secao: c.secao, topicos: c.topicos });
}
for (const [modo, valor] of Object.entries(s.consumo_energia ?? {})) {
const base = modo.replace(/_cpu.*|_wifi.*/, "");
const label = ROTULOS_ENERGIA[modo] ?? ROTULOS_ENERGIA[base] ?? modo.replace(/_/g, " ");
specs.push({ label: `功耗:${label}`, valor: String(valor), secao: "energia", topicos: ["consumo"] });
}
saida[chave] = {
nome: s.nome_completo ?? chave,
specs,
pinos: (conexoes[chave] ?? []).map((p) => ({
n: String(p.numero),
nome: p.nome,
f: p.funcoes ?? [],
c: p.categorias ?? [],
a: p.avisos ?? [],
})),
};
}
return saida;
}