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
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:
1 parent
ae61416468
commit
5a9fe676fc
61 files changed
+2517
-920
No files matched your search
@@ -166,7 +166,7 @@ export function montarConhecimento(series, conexoes) {
|
||||
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: `Consumo: ${label}`, valor: String(valor), secao: "energia", topicos: ["consumo"] });
|
||||
specs.push({ label: `Power: ${label}`, valor: String(valor), secao: "energia", topicos: ["consumo"] });
|
||||
}
|
||||
saida[chave] = {
|
||||
nome: s.nome_completo ?? chave,
|
||||
|
||||
@@ -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"],
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
+79
-24
@@ -1,4 +1,5 @@
|
||||
import { TOPICOS, normalizar } from "./searchTopics.js";
|
||||
import { BUSCA_I18N } from "./searchI18n.js";
|
||||
|
||||
/**
|
||||
* Motor da busca inteligente (puro: sem React nem DOM).
|
||||
@@ -21,6 +22,26 @@ const INTENCAO_DADOS = new Set([
|
||||
"quanto", "quantos", "quantas", "capacidade", "limite", "limites", "tem", "possui", "suporta",
|
||||
]);
|
||||
|
||||
const CJK = /[\u3400-\u9fff]/;
|
||||
const INTENCAO_PINOS_ZH = ["引脚", "管脚", "针脚", "脚位"];
|
||||
const INTENCAO_DADOS_ZH = ["规格", "参数", "容量", "多少", "支持吗", "是否支持", "有吗"];
|
||||
const STOP_ZH = new Set(["的", "吗", "呢", "啊", "吧", "了", "是", "什么", "哪个", "哪些", "怎么", "如何", "有", "和", "与", "在", "要", "想", "我", "请", "能", "可以"]);
|
||||
|
||||
/** Palavras de um trecho em chinês (Intl.Segmenter; sem ele, bigramas de caracteres). */
|
||||
function segmentar(texto) {
|
||||
let palavras = [];
|
||||
try {
|
||||
const seg = new Intl.Segmenter("zh", { granularity: "word" });
|
||||
palavras = [...seg.segment(texto)].filter((s) => s.isWordLike).map((s) => s.segment);
|
||||
} catch {
|
||||
const cs = [...texto];
|
||||
palavras = cs.length <= 2 ? [texto] : cs.slice(0, -1).map((c, i) => c + cs[i + 1]);
|
||||
}
|
||||
return palavras.filter((w) => !STOP_ZH.has(w));
|
||||
}
|
||||
|
||||
const fmt = (modelo, v) => modelo.replace(/\{(\w+)\}/g, (_, k) => String(v[k] ?? ""));
|
||||
|
||||
const EXEMPLOS_TOPICOS = ["flash", "psram", "usb", "adc", "i2c", "deep sleep", "wifi", "strapping"];
|
||||
|
||||
/** Distância de edição com corte: devolve > max assim que passa do limite. */
|
||||
@@ -45,7 +66,7 @@ const palavrasDe = (texto) => texto.split(/[^a-z0-9]+/).filter((w) => w.length >
|
||||
|
||||
/** Normaliza o payload do servidor uma única vez, na abertura da busca. */
|
||||
export function preparar(dados) {
|
||||
if (!dados) return { itens: [], series: {}, porFuncao: new Map(), aliases: new Map(), chaves: [] };
|
||||
if (!dados) return { itens: [], series: {}, porFuncao: new Map(), aliases: new Map(), chaves: [], locale: "pt", topicosLoc: null };
|
||||
|
||||
const itensRaw = Array.isArray(dados) ? dados : (dados.itens ?? []);
|
||||
const seriesRaw = Array.isArray(dados) ? {} : (dados.series ?? {});
|
||||
@@ -90,11 +111,15 @@ export function preparar(dados) {
|
||||
if (k.startsWith("esp32-")) aliases.set(k.slice(6), chave);
|
||||
}
|
||||
|
||||
return { itens, series, porFuncao, aliases, chaves: Object.keys(series) };
|
||||
return { itens, series, porFuncao, aliases, chaves: Object.keys(series), locale: Array.isArray(dados) ? "pt" : (dados.locale ?? "pt"), topicosLoc: Array.isArray(dados) ? null : (dados.topicos ?? null) };
|
||||
}
|
||||
|
||||
/** Tenta casar um termo do dicionário com os tokens livres. Devolve { idx[], qualidade } ou null. */
|
||||
function casarTermo(termo, livres) {
|
||||
if (CJK.test(termo)) {
|
||||
for (const { t, i } of livres) if (CJK.test(t) && t.includes(termo)) return { idx: [i], qualidade: 3 + termo.length / 10, cjk: true };
|
||||
return null;
|
||||
}
|
||||
const partes = termo.split(" ");
|
||||
if (partes.length > 1) {
|
||||
for (let i = 0; i + partes.length <= livres.length; i++) {
|
||||
@@ -115,7 +140,9 @@ function casarTermo(termo, livres) {
|
||||
export function interpretar(indice, consulta) {
|
||||
const bruto = normalizar(consulta)
|
||||
.replace(/gpio\s*-?\s*(\d+)/g, "gpio$1")
|
||||
.replace(/[^a-z0-9.+\-_ ]/g, " ");
|
||||
.replace(/([\u3400-\u9fff])([a-z0-9])/g, "$1 $2")
|
||||
.replace(/([a-z0-9])([\u3400-\u9fff])/g, "$1 $2")
|
||||
.replace(/[^a-z0-9.+\-_ \u3400-\u9fff]/g, " ");
|
||||
const tokens = bruto.split(/\s+/).filter(Boolean);
|
||||
const usados = new Set();
|
||||
|
||||
@@ -138,6 +165,17 @@ export function interpretar(indice, consulta) {
|
||||
const gpios = [];
|
||||
let querPinos = false;
|
||||
let querDados = false;
|
||||
// Chinês não separa palavras por espaço: tira do trecho as palavras de intenção.
|
||||
tokens.forEach((t, i) => {
|
||||
if (!CJK.test(t)) return;
|
||||
let resto = t;
|
||||
for (const w of INTENCAO_PINOS_ZH) if (resto.includes(w)) { querPinos = true; resto = resto.split(w).join(""); }
|
||||
for (const w of INTENCAO_DADOS_ZH) if (resto.includes(w)) { querDados = true; resto = resto.split(w).join(""); }
|
||||
if (resto !== t) {
|
||||
tokens[i] = resto;
|
||||
if (!resto) usados.add(i);
|
||||
}
|
||||
});
|
||||
tokens.forEach((t, i) => {
|
||||
if (/^gpio\d+$/.test(t)) {
|
||||
gpios.push(t);
|
||||
@@ -158,7 +196,8 @@ export function interpretar(indice, consulta) {
|
||||
const candidatos = [];
|
||||
for (const topico of TOPICOS) {
|
||||
let melhor = null;
|
||||
for (const termo of topico.termos) {
|
||||
const extras = indice.topicosLoc?.[topico.id]?.termos;
|
||||
for (const termo of extras ? [...topico.termos, ...extras] : topico.termos) {
|
||||
const m = casarTermo(normalizar(termo), livres);
|
||||
if (m && (!melhor || m.qualidade > melhor.qualidade)) melhor = m;
|
||||
}
|
||||
@@ -166,8 +205,15 @@ export function interpretar(indice, consulta) {
|
||||
}
|
||||
candidatos.sort((a, b) => b.qualidade - a.qualidade);
|
||||
const topicos = [];
|
||||
const cjkUsados = [];
|
||||
for (const c of candidatos) {
|
||||
if (topicos.length >= 3) break;
|
||||
if (c.cjk) {
|
||||
// Um mesmo trecho em chinês pode citar vários assuntos.
|
||||
topicos.push(c.topico);
|
||||
cjkUsados.push(...c.idx);
|
||||
continue;
|
||||
}
|
||||
if (c.idx.some((i) => usados.has(i))) continue;
|
||||
c.idx.forEach((i) => usados.add(i));
|
||||
topicos.push(c.topico);
|
||||
@@ -183,7 +229,8 @@ export function interpretar(indice, consulta) {
|
||||
}
|
||||
});
|
||||
|
||||
const restantes = tokens.filter((_, i) => !usados.has(i));
|
||||
cjkUsados.forEach((i) => usados.add(i));
|
||||
const restantes = tokens.filter((_, i) => !usados.has(i)).flatMap((t) => (CJK.test(t) ? segmentar(t) : [t]));
|
||||
return { tokens, chips, topicos, gpios, funcoes, restantes, querPinos, querDados };
|
||||
}
|
||||
|
||||
@@ -206,11 +253,17 @@ function pinosDoTopico(serie, topico) {
|
||||
return { forte, fraco };
|
||||
}
|
||||
|
||||
const hrefPinos = (chave, pinos, motivo) =>
|
||||
`/series/${chave}?pinos=${pinos.map((p) => p.n).join(",")}&motivo=${encodeURIComponent(motivo)}#connections`;
|
||||
const hrefPinos = (I, chave, pinos, motivo) =>
|
||||
`${I.rotas.series}/${chave}?pinos=${pinos.map((p) => p.n).join(",")}&motivo=${encodeURIComponent(motivo)}#connections`;
|
||||
|
||||
function respostas(indice, it) {
|
||||
const saida = [];
|
||||
const I = BUSCA_I18N[indice.locale] ?? BUSCA_I18N.pt;
|
||||
const T = I.t;
|
||||
const loc = (topico) => ({
|
||||
nome: indice.topicosLoc?.[topico.id]?.nome ?? topico.nome,
|
||||
rotulo: indice.topicosLoc?.[topico.id]?.pinoRotulo ?? topico.pinoRotulo,
|
||||
});
|
||||
const alvos = it.chips.slice(0, 2);
|
||||
|
||||
for (const chave of alvos) {
|
||||
@@ -218,14 +271,15 @@ function respostas(indice, it) {
|
||||
if (!serie) continue;
|
||||
|
||||
for (const topico of it.topicos.slice(0, 2)) {
|
||||
const tn = loc(topico);
|
||||
const specs = serie.specs.filter((s) => s.topicos.includes(topico.id));
|
||||
const cartaoSpec = specs.length
|
||||
? {
|
||||
tipo: "resposta",
|
||||
titulo: `${topico.nome} no ${serie.nome}`,
|
||||
descricao: "Dados da série",
|
||||
titulo: fmt(T.specTitulo, { topico: tn.nome, serie: serie.nome }),
|
||||
descricao: T.specDesc,
|
||||
linhas: specs.slice(0, 5).map((s) => ({ k: s.label, v: s.valor })),
|
||||
href: `/series/${chave}#${specs[0].secao}`,
|
||||
href: `${I.rotas.series}/${chave}#${specs[0].secao}`,
|
||||
}
|
||||
: null;
|
||||
|
||||
@@ -234,19 +288,19 @@ function respostas(indice, it) {
|
||||
const cartaoPinos = principais.length
|
||||
? {
|
||||
tipo: "pino",
|
||||
titulo: `Pinos do ${serie.nome} ${topico.pinoRotulo}`,
|
||||
titulo: fmt(T.pinosTitulo, { serie: serie.nome, rotulo: tn.rotulo }),
|
||||
descricao:
|
||||
forte.length && fraco.length
|
||||
? `${forte.length} ocupados + ${fraco.length} que dependem do modo de uso (ex.: SPI de 8 linhas) · abre o diagrama filtrado`
|
||||
? fmt(T.pinosMistos, { forte: forte.length, fraco: fraco.length })
|
||||
: forte.length
|
||||
? `${forte.length} ${forte.length === 1 ? "pino" : "pinos"} · abre o diagrama já filtrado`
|
||||
: `${fraco.length} pinos que só são afetados em certos modos de uso · abre o diagrama filtrado`,
|
||||
? fmt(forte.length === 1 ? T.pinoUm : T.pinosVarios, { n: forte.length })
|
||||
: fmt(T.pinosFraco, { n: fraco.length }),
|
||||
chips: forte
|
||||
.slice(0, 12)
|
||||
.map(rotuloPino)
|
||||
.concat(forte.length > 12 ? [`+${forte.length - 12}`] : [])
|
||||
.concat(fraco.length && forte.length ? [`+${fraco.length} condicionais`] : forte.length ? [] : fraco.slice(0, 10).map(rotuloPino)),
|
||||
href: hrefPinos(chave, [...forte, ...fraco], `${topico.nome}: pinos ${topico.pinoRotulo}`),
|
||||
.concat(fraco.length && forte.length ? [fmt(T.condicionais, { n: fraco.length })] : forte.length ? [] : fraco.slice(0, 10).map(rotuloPino)),
|
||||
href: hrefPinos(I, chave, [...forte, ...fraco], fmt(T.motivoTopico, { topico: tn.nome, rotulo: tn.rotulo })),
|
||||
}
|
||||
: null;
|
||||
|
||||
@@ -257,13 +311,13 @@ function respostas(indice, it) {
|
||||
if (it.querPinos && serie.pinos.length) {
|
||||
saida.push({
|
||||
tipo: "pino",
|
||||
titulo: `Diagrama de pinos do ${serie.nome}`,
|
||||
descricao: `${serie.pinos.length} pinos com funções, restrições e avisos`,
|
||||
href: `/series/${chave}#connections`,
|
||||
titulo: fmt(T.diagTitulo, { serie: serie.nome }),
|
||||
descricao: fmt(T.diagDesc, { n: serie.pinos.length }),
|
||||
href: `${I.rotas.series}/${chave}#connections`,
|
||||
});
|
||||
}
|
||||
if (it.querDados) {
|
||||
saida.push({ tipo: "resposta", titulo: `Especificações do ${serie.nome}`, descricao: "Processador, memória, conectividade, periféricos e mais", href: `/series/${chave}` });
|
||||
saida.push({ tipo: "resposta", titulo: fmt(T.especTitulo, { serie: serie.nome }), descricao: T.especDesc, href: `${I.rotas.series}/${chave}` });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,6 +325,7 @@ function respostas(indice, it) {
|
||||
// Assunto sem chip: panorama por série ("qual série tem PSRAM?")
|
||||
if (!alvos.length && it.topicos.length) {
|
||||
const topico = it.topicos[0];
|
||||
const tn = loc(topico);
|
||||
const linhas = [];
|
||||
for (const chave of indice.chaves) {
|
||||
const serie = indice.series[chave];
|
||||
@@ -278,7 +333,7 @@ function respostas(indice, it) {
|
||||
if (spec) linhas.push({ k: serie.nome, v: spec.valor.length > 46 ? `${spec.valor.slice(0, 45)}…` : spec.valor });
|
||||
}
|
||||
if (linhas.length > 1) {
|
||||
saida.push({ tipo: "resposta", titulo: `${topico.nome} em cada série`, descricao: "Comparativo rápido · adicione o chip na busca para detalhar", linhas, href: "/comparacao" });
|
||||
saida.push({ tipo: "resposta", titulo: fmt(T.emCada, { topico: tn.nome }), descricao: T.compDesc, linhas, href: I.rotas.comparacao });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,9 +346,9 @@ function respostas(indice, it) {
|
||||
const serie = indice.series[chave];
|
||||
saida.push({
|
||||
tipo: "pino",
|
||||
titulo: `${rotuloPino(pino)} no ${serie.nome}`,
|
||||
titulo: fmt(T.pinoNo, { pino: rotuloPino(pino), serie: serie.nome }),
|
||||
descricao: [pino.f.join(" · "), pino.a[0]].filter(Boolean).join(" — "),
|
||||
href: hrefPinos(chave, [pino], `Pino ${rotuloPino(pino)}`),
|
||||
href: hrefPinos(I, chave, [pino], fmt(T.motivoPino, { pino: rotuloPino(pino) })),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -331,7 +386,7 @@ export function buscar(indice, consulta) {
|
||||
const it = interpretar(indice, consulta);
|
||||
const interpretacao = {
|
||||
chips: it.chips.map((c) => ({ chave: c, nome: indice.series[c]?.nome ?? c })),
|
||||
topicos: it.topicos.map((t) => ({ id: t.id, nome: t.nome })),
|
||||
topicos: it.topicos.map((t) => ({ id: t.id, nome: indice.topicosLoc?.[t.id]?.nome ?? t.nome })),
|
||||
};
|
||||
|
||||
const smart = respostas(indice, it).map((r, i) => ({ id: `r${i}`, keywords: "", ...r }));
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* Textos e rotas das respostas diretas da busca, por idioma.
|
||||
*
|
||||
* Módulo puro (sem alias de import): o servidor monta o índice com ele e o
|
||||
* motor (`searchEngine.js`) só preenche os {placeholders}. Idioma sem entrada
|
||||
* cai no português.
|
||||
*/
|
||||
|
||||
const base = (loc, series, comparacao) => ({ series: `/${loc}/${series}`, comparacao: `/${loc}/${comparacao}` });
|
||||
|
||||
export const BUSCA_I18N = {
|
||||
pt: {
|
||||
rotas: base("pt", "series", "comparacao"),
|
||||
t: {
|
||||
specTitulo: "{topico} no {serie}",
|
||||
specDesc: "Dados da série",
|
||||
pinosTitulo: "Pinos do {serie} {rotulo}",
|
||||
pinosMistos: "{forte} ocupados + {fraco} que dependem do modo de uso (ex.: SPI de 8 linhas) · abre o diagrama filtrado",
|
||||
pinoUm: "{n} pino · abre o diagrama já filtrado",
|
||||
pinosVarios: "{n} pinos · abre o diagrama já filtrado",
|
||||
pinosFraco: "{n} pinos que só são afetados em certos modos de uso · abre o diagrama filtrado",
|
||||
condicionais: "+{n} condicionais",
|
||||
motivoTopico: "{topico}: pinos {rotulo}",
|
||||
diagTitulo: "Diagrama de pinos do {serie}",
|
||||
diagDesc: "{n} pinos com funções, restrições e avisos",
|
||||
especTitulo: "Especificações do {serie}",
|
||||
especDesc: "Processador, memória, conectividade, periféricos e mais",
|
||||
emCada: "{topico} em cada série",
|
||||
compDesc: "Comparativo rápido · adicione o chip na busca para detalhar",
|
||||
pinoNo: "{pino} no {serie}",
|
||||
motivoPino: "Pino {pino}",
|
||||
},
|
||||
},
|
||||
en: {
|
||||
rotas: base("en", "series", "compare"),
|
||||
t: {
|
||||
specTitulo: "{topico} on the {serie}",
|
||||
specDesc: "Series data",
|
||||
pinosTitulo: "{serie}: {rotulo}",
|
||||
pinosMistos: "{forte} occupied + {fraco} that depend on the usage mode (e.g. 8-line SPI) · opens the filtered diagram",
|
||||
pinoUm: "{n} pin · opens the already filtered diagram",
|
||||
pinosVarios: "{n} pins · opens the already filtered diagram",
|
||||
pinosFraco: "{n} pins only affected in certain usage modes · opens the filtered diagram",
|
||||
condicionais: "+{n} conditional",
|
||||
motivoTopico: "{topico}: {rotulo}",
|
||||
diagTitulo: "{serie} pinout diagram",
|
||||
diagDesc: "{n} pins with functions, restrictions and warnings",
|
||||
especTitulo: "{serie} specifications",
|
||||
especDesc: "Processor, memory, connectivity, peripherals and more",
|
||||
emCada: "{topico} across all series",
|
||||
compDesc: "Quick comparison · add the chip to your search for details",
|
||||
pinoNo: "{pino} on the {serie}",
|
||||
motivoPino: "Pin {pino}",
|
||||
},
|
||||
},
|
||||
es: {
|
||||
rotas: base("es", "series", "comparacion"),
|
||||
t: {
|
||||
specTitulo: "{topico} en el {serie}",
|
||||
specDesc: "Datos de la serie",
|
||||
pinosTitulo: "Pines del {serie} {rotulo}",
|
||||
pinosMistos: "{forte} ocupados + {fraco} que dependen del modo de uso (p. ej., SPI de 8 líneas) · abre el diagrama filtrado",
|
||||
pinoUm: "{n} pin · abre el diagrama ya filtrado",
|
||||
pinosVarios: "{n} pines · abre el diagrama ya filtrado",
|
||||
pinosFraco: "{n} pines que solo se ven afectados en ciertos modos de uso · abre el diagrama filtrado",
|
||||
condicionais: "+{n} condicionales",
|
||||
motivoTopico: "{topico}: pines {rotulo}",
|
||||
diagTitulo: "Diagrama de pines del {serie}",
|
||||
diagDesc: "{n} pines con funciones, restricciones y avisos",
|
||||
especTitulo: "Especificaciones del {serie}",
|
||||
especDesc: "Procesador, memoria, conectividad, periféricos y más",
|
||||
emCada: "{topico} en cada serie",
|
||||
compDesc: "Comparativa rápida · añade el chip a la búsqueda para ver el detalle",
|
||||
pinoNo: "{pino} en el {serie}",
|
||||
motivoPino: "Pin {pino}",
|
||||
},
|
||||
},
|
||||
fr: {
|
||||
rotas: base("fr", "series", "comparaison"),
|
||||
t: {
|
||||
specTitulo: "{topico} sur le {serie}",
|
||||
specDesc: "Données de la série",
|
||||
pinosTitulo: "Broches du {serie} {rotulo}",
|
||||
pinosMistos: "{forte} occupées + {fraco} qui dépendent du mode d'utilisation (ex. : SPI 8 lignes) · ouvre le schéma filtré",
|
||||
pinoUm: "{n} broche · ouvre le schéma déjà filtré",
|
||||
pinosVarios: "{n} broches · ouvre le schéma déjà filtré",
|
||||
pinosFraco: "{n} broches concernées seulement dans certains modes d'utilisation · ouvre le schéma filtré",
|
||||
condicionais: "+{n} conditionnelles",
|
||||
motivoTopico: "{topico} : broches {rotulo}",
|
||||
diagTitulo: "Schéma des broches du {serie}",
|
||||
diagDesc: "{n} broches avec fonctions, restrictions et avertissements",
|
||||
especTitulo: "Caractéristiques du {serie}",
|
||||
especDesc: "Processeur, mémoire, connectivité, périphériques et plus",
|
||||
emCada: "{topico} dans chaque série",
|
||||
compDesc: "Comparatif rapide · ajoutez la puce à la recherche pour détailler",
|
||||
pinoNo: "{pino} sur le {serie}",
|
||||
motivoPino: "Broche {pino}",
|
||||
},
|
||||
},
|
||||
de: {
|
||||
rotas: base("de", "serien", "vergleich"),
|
||||
t: {
|
||||
specTitulo: "{topico} beim {serie}",
|
||||
specDesc: "Seriendaten",
|
||||
pinosTitulo: "{serie}: {rotulo}",
|
||||
pinosMistos: "{forte} belegt + {fraco} abhängig vom Nutzungsmodus (z. B. 8-Bit-SPI) · öffnet das gefilterte Diagramm",
|
||||
pinoUm: "{n} Pin · öffnet das bereits gefilterte Diagramm",
|
||||
pinosVarios: "{n} Pins · öffnet das bereits gefilterte Diagramm",
|
||||
pinosFraco: "{n} Pins, die nur in bestimmten Nutzungsmodi betroffen sind · öffnet das gefilterte Diagramm",
|
||||
condicionais: "+{n} bedingte",
|
||||
motivoTopico: "{topico}: {rotulo}",
|
||||
diagTitulo: "Pin-Diagramm des {serie}",
|
||||
diagDesc: "{n} Pins mit Funktionen, Einschränkungen und Hinweisen",
|
||||
especTitulo: "Spezifikationen des {serie}",
|
||||
especDesc: "Prozessor, Speicher, Konnektivität, Peripherie und mehr",
|
||||
emCada: "{topico} in jeder Serie",
|
||||
compDesc: "Schnellvergleich · fügen Sie den Chip zur Suche hinzu, um Details zu sehen",
|
||||
pinoNo: "{pino} beim {serie}",
|
||||
motivoPino: "Pin {pino}",
|
||||
},
|
||||
},
|
||||
"zh-CN": {
|
||||
rotas: base("zh-CN", "series", "compare"),
|
||||
t: {
|
||||
specTitulo: "{serie}:{topico}",
|
||||
specDesc: "系列数据",
|
||||
pinosTitulo: "{serie} 的引脚:{rotulo}",
|
||||
pinosMistos: "{forte} 个被占用 + {fraco} 个取决于使用模式(例如八线 SPI)· 打开已筛选的引脚图",
|
||||
pinoUm: "{n} 个引脚 · 打开已筛选的引脚图",
|
||||
pinosVarios: "{n} 个引脚 · 打开已筛选的引脚图",
|
||||
pinosFraco: "{n} 个引脚仅在某些使用模式下受影响 · 打开已筛选的引脚图",
|
||||
condicionais: "另有 {n} 个有条件",
|
||||
motivoTopico: "{topico}:{rotulo}",
|
||||
diagTitulo: "{serie} 引脚图",
|
||||
diagDesc: "{n} 个引脚,含功能、限制与警告",
|
||||
especTitulo: "{serie} 规格",
|
||||
especDesc: "处理器、内存、无线连接、外设等",
|
||||
emCada: "{topico}:各系列对比",
|
||||
compDesc: "快速对比 · 在搜索中加上芯片可查看详情",
|
||||
pinoNo: "{serie} 的 {pino}",
|
||||
motivoPino: "引脚 {pino}",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const buscaI18n = (locale) => BUSCA_I18N[locale] ?? BUSCA_I18N.pt;
|
||||
+47
-6
@@ -33,6 +33,20 @@ import { errosCatalogo as errosDe } from "@/lib/data/de/diagnostico";
|
||||
import { COMPONENTES_REGISTRY as componentesDe } from "@/lib/data/de/componentes";
|
||||
import { montarConhecimento as montarConhecimentoDe } from "@/lib/data/de/topicos";
|
||||
|
||||
import seriesDataZh from "@/data/zh-CN/series.json";
|
||||
import frameworksDataZh from "@/data/zh-CN/frameworks.json";
|
||||
import { categoriasGlossario as glossarioZh } from "@/lib/data/zh-CN/glossario";
|
||||
import { errosCatalogo as errosZh } from "@/lib/data/zh-CN/diagnostico";
|
||||
import { COMPONENTES_REGISTRY as componentesZh } from "@/lib/data/zh-CN/componentes";
|
||||
import { montarConhecimento as montarConhecimentoZh } from "@/lib/data/zh-CN/topicos";
|
||||
|
||||
// Nomes, rótulos e sinônimos dos assuntos no idioma da página (o motor só traz os em português).
|
||||
import { TOPICOS as TOPICOS_EN } from "@/lib/data/en/topicos";
|
||||
import { TOPICOS as TOPICOS_ES } from "@/lib/data/es/topicos";
|
||||
import { TOPICOS as TOPICOS_FR } from "@/lib/data/fr/topicos";
|
||||
import { TOPICOS as TOPICOS_DE } from "@/lib/data/de/topicos";
|
||||
import { TOPICOS as TOPICOS_ZH } from "@/lib/data/zh-CN/topicos";
|
||||
|
||||
import { readFileSync, existsSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
@@ -97,6 +111,19 @@ const PAGINAS_FR = [
|
||||
{ titulo: "À Propos du Projet", descricao: "Histoire, auteur et open source", href: "/fr/a-propos", keywords: "auteur contact open source" },
|
||||
];
|
||||
|
||||
const PAGINAS_ZH = [
|
||||
{ titulo: "首页", descricao: "ESPDocs 首页", href: "/zh-CN", keywords: "首页 主页 home" },
|
||||
{ titulo: "全部系列", descricao: "每个 ESP32 系列的引脚、规格与限制", href: "/zh-CN/series", keywords: "芯片 引脚 规格 pinout" },
|
||||
{ titulo: "系列对比", descricao: "最多并排对比 4 个型号", href: "/zh-CN/compare", keywords: "对比 比较 差异" },
|
||||
{ titulo: "开发板目录", descricao: "开发板、引脚与购买渠道", href: "/zh-CN/catalog", keywords: "开发板 devkit 购买" },
|
||||
{ titulo: "智能选型", descricao: "为你的项目找到合适的芯片", href: "/zh-CN/selector", keywords: "选型 推荐 测验" },
|
||||
{ titulo: "故障诊断", descricao: "排查 Brownout、启动循环、看门狗和崩溃", href: "/zh-CN/diagnostics", keywords: "故障 错误 崩溃 问题 bug" },
|
||||
{ titulo: "框架与 SDK", descricao: "ESP-IDF、Arduino、Rust、RainMaker 等", href: "/zh-CN/frameworks", keywords: "sdk 开发框架" },
|
||||
{ titulo: "Component Registry", descricao: "驱动目录与 idf_component.yml 生成器", href: "/zh-CN/components", keywords: "库 驱动 组件 yml" },
|
||||
{ titulo: "技术术语表", descricao: "关键的硬件与软件概念", href: "/zh-CN/glossary", keywords: "术语 词典 定义 含义" },
|
||||
{ titulo: "关于本项目", descricao: "历史、作者与开源", href: "/zh-CN/about", keywords: "作者 联系 开源" },
|
||||
];
|
||||
|
||||
const PAGINAS_DE = [
|
||||
{ titulo: "Startseite", descricao: "ESPDocs Startseite", href: "/de", keywords: "startseite home" },
|
||||
{ titulo: "Alle Serien", descricao: "Pinbelegungen, Spezifikationen und Einschränkungen für jede ESP32-Serie", href: "/de/serien", keywords: "chips pinbelegung spezifikationen pinout" },
|
||||
@@ -117,6 +144,7 @@ export function construirIndiceBusca(locale = "pt") {
|
||||
const isEs = locale === "es";
|
||||
const isFr = locale === "fr";
|
||||
const isDe = locale === "de";
|
||||
const isZh = locale === "zh-CN";
|
||||
|
||||
let paginas = PAGINAS_PT;
|
||||
let seriesData = seriesDataPt;
|
||||
@@ -158,13 +186,21 @@ export function construirIndiceBusca(locale = "pt") {
|
||||
errosCatalogo = errosDe;
|
||||
componentes = componentesDe;
|
||||
montarConhecimento = montarConhecimentoDe;
|
||||
} else if (isZh) {
|
||||
paginas = PAGINAS_ZH;
|
||||
seriesData = seriesDataZh;
|
||||
frameworksData = frameworksDataZh;
|
||||
categoriasGlossario = glossarioZh;
|
||||
errosCatalogo = errosZh;
|
||||
componentes = componentesZh;
|
||||
montarConhecimento = montarConhecimentoZh;
|
||||
}
|
||||
|
||||
const slugSeries = isDe ? "/de/serien" : isFr ? "/fr/series" : isEn ? "/en/series" : isEs ? "/es/series" : "/series";
|
||||
const slugFrameworks = isDe ? "/de/frameworks" : isFr ? "/fr/frameworks" : isEn ? "/en/frameworks" : isEs ? "/es/frameworks" : "/frameworks";
|
||||
const slugGlossario = isDe ? "/de/glossar" : isFr ? "/fr/glossaire" : isEn ? "/en/glossary" : isEs ? "/es/glosario" : "/glossario";
|
||||
const slugDiagnostico = isDe ? "/de/diagnose" : isFr ? "/fr/diagnostic" : isEn ? "/en/diagnostics" : isEs ? "/es/diagnostico" : "/diagnostico";
|
||||
const slugComponentes = isDe ? "/de/komponenten" : isFr ? "/fr/composants" : isEn ? "/en/components" : isEs ? "/es/componentes" : "/componentes";
|
||||
const slugSeries = isZh ? "/zh-CN/series" : isDe ? "/de/serien" : isFr ? "/fr/series" : isEn ? "/en/series" : isEs ? "/es/series" : "/series";
|
||||
const slugFrameworks = isZh ? "/zh-CN/frameworks" : isDe ? "/de/frameworks" : isFr ? "/fr/frameworks" : isEn ? "/en/frameworks" : isEs ? "/es/frameworks" : "/frameworks";
|
||||
const slugGlossario = isZh ? "/zh-CN/glossary" : isDe ? "/de/glossar" : isFr ? "/fr/glossaire" : isEn ? "/en/glossary" : isEs ? "/es/glosario" : "/glossario";
|
||||
const slugDiagnostico = isZh ? "/zh-CN/diagnostics" : isDe ? "/de/diagnose" : isFr ? "/fr/diagnostic" : isEn ? "/en/diagnostics" : isEs ? "/es/diagnostico" : "/diagnostico";
|
||||
const slugComponentes = isZh ? "/zh-CN/components" : isDe ? "/de/komponenten" : isFr ? "/fr/composants" : isEn ? "/en/components" : isEs ? "/es/componentes" : "/componentes";
|
||||
|
||||
const itens = [];
|
||||
|
||||
@@ -233,7 +269,7 @@ export function construirIndiceBusca(locale = "pt") {
|
||||
? path.join(process.cwd(), "data", "es", "conexoes")
|
||||
: isFr
|
||||
? path.join(process.cwd(), "data", "fr", "conexoes")
|
||||
: isDe
|
||||
: isZh ? path.join(process.cwd(), "data", "zh-CN", "conexoes") : isDe
|
||||
? path.join(process.cwd(), "data", "de", "conexoes")
|
||||
: path.join(process.cwd(), "public", "conexoes");
|
||||
const arquivo = path.join(pastaConexoes, `${chave}.json`);
|
||||
@@ -245,7 +281,12 @@ export function construirIndiceBusca(locale = "pt") {
|
||||
}
|
||||
}
|
||||
|
||||
const topicosLoc = { en: TOPICOS_EN, es: TOPICOS_ES, fr: TOPICOS_FR, de: TOPICOS_DE, "zh-CN": TOPICOS_ZH }[locale];
|
||||
return {
|
||||
locale,
|
||||
topicos: topicosLoc
|
||||
? Object.fromEntries(topicosLoc.map((tp) => [tp.id, { nome: tp.nome, pinoRotulo: tp.pinoRotulo, termos: tp.termos }]))
|
||||
: null,
|
||||
itens: itens.map((item, i) => ({ id: i, ...item })),
|
||||
series: montarConhecimento(seriesData, conexoes),
|
||||
};
|
||||
|
||||
+37
-31
@@ -97,9 +97,10 @@ export const jsonLd = {
|
||||
const isEs = locale === "es";
|
||||
const isFr = locale === "fr";
|
||||
const isDe = locale === "de";
|
||||
const orgAnchor = isEn ? "organization" : isEs ? "organizacion" : (isFr || isDe) ? "organisation" : "organizacao";
|
||||
const isZh = locale === "zh-CN";
|
||||
const orgAnchor = isZh ? "organization" : isEn ? "organization" : isEs ? "organizacion" : (isFr || isDe) ? "organisation" : "organizacao";
|
||||
const authorAnchor = isEn ? "author" : isFr ? "auteur" : "autor";
|
||||
const inLang = isEn ? "en" : isEs ? "es-419" : isFr ? "fr" : isDe ? "de" : "pt-BR";
|
||||
const inLang = isEn ? "en" : isEs ? "es-419" : isFr ? "fr" : isZh ? "zh-CN" : isDe ? "de" : "pt-BR";
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
@@ -115,7 +116,7 @@ export const jsonLd = {
|
||||
? "Documentación del ecosistema ESP32: especificaciones, patillaje, comparación y selección de series."
|
||||
: isFr
|
||||
? "Documentation de l'écosystème ESP32 : spécifications, brochages, comparaison et sélection de séries."
|
||||
: isDe
|
||||
: isZh ? "ESP32 生态文档(简体中文):规格、引脚、对比与系列选型。" : isDe
|
||||
? "Dokumentation des ESP32-Ökosystems: Spezifikationen, Pinbelegung, Vergleich und Serienauswahl."
|
||||
: "Documentação do ecossistema ESP32 em português brasileiro: especificações, pinagem, comparação e seleção de séries.",
|
||||
publisher: { "@id": `${SITE.url}/#${orgAnchor}` },
|
||||
@@ -166,33 +167,34 @@ export const jsonLd = {
|
||||
const isEs = locale === "es";
|
||||
const isFr = locale === "fr";
|
||||
const isDe = locale === "de";
|
||||
const isZh = locale === "zh-CN";
|
||||
const prop = (nome, valor) =>
|
||||
valor ? { "@type": "PropertyValue", name: nome, value: String(valor) } : null;
|
||||
|
||||
const propriedades = [
|
||||
prop(isEn ? "Manufacturer" : isEs ? "Fabricante" : isFr ? "Fabricant" : isDe ? "Hersteller" : "Fabricante", "Espressif Systems"),
|
||||
prop(isEn ? "Architecture" : isEs ? "Arquitectura" : isFr ? "Architecture" : isDe ? "Architektur" : "Arquitetura"),
|
||||
prop(isEn ? "Cores" : isEs ? "Núcleos" : isFr ? "Cœurs" : isDe ? "Kerne" : "Núcleos", serie.nucleos),
|
||||
prop(isEn ? "Max frequency" : isEs ? "Frecuencia máxima" : isFr ? "Fréquence maximale" : isDe ? "Maximale Frequenz" : "Frequência máxima", serie.frequencia),
|
||||
prop(isEn ? "Manufacturer" : isEs ? "Fabricante" : isFr ? "Fabricant" : isZh ? "制造商" : isDe ? "Hersteller" : "Fabricante", "Espressif Systems"),
|
||||
prop(isEn ? "Architecture" : isEs ? "Arquitectura" : isFr ? "Architecture" : isZh ? "架构" : isDe ? "Architektur" : "Arquitetura"),
|
||||
prop(isEn ? "Cores" : isEs ? "Núcleos" : isFr ? "Cœurs" : isZh ? "内核数" : isDe ? "Kerne" : "Núcleos", serie.nucleos),
|
||||
prop(isEn ? "Max frequency" : isEs ? "Frecuencia máxima" : isFr ? "Fréquence maximale" : isZh ? "最高频率" : isDe ? "Maximale Frequenz" : "Frequência máxima", serie.frequencia),
|
||||
prop("SRAM", serie.memoria_sram),
|
||||
prop("RTC SRAM", serie.memoria_sram_rtc),
|
||||
prop(isEn ? "Supported Flash" : isEs ? "Flash soportada" : isFr ? "Flash prise en charge" : isDe ? "Unterstützter Flash" : "Flash suportada", serie.flash_suportada),
|
||||
prop(isEn ? "Supported PSRAM" : isEs ? "PSRAM soportada" : isFr ? "PSRAM prise en charge" : isDe ? "Unterstütztes PSRAM" : "PSRAM suportada", serie.psram_suportada),
|
||||
prop(isEn ? "Supported Flash" : isEs ? "Flash soportada" : isFr ? "Flash prise en charge" : isZh ? "支持的闪存" : isDe ? "Unterstützter Flash" : "Flash suportada", serie.flash_suportada),
|
||||
prop(isEn ? "Supported PSRAM" : isEs ? "PSRAM soportada" : isFr ? "PSRAM prise en charge" : isZh ? "支持的 PSRAM" : isDe ? "Unterstütztes PSRAM" : "PSRAM suportada", serie.psram_suportada),
|
||||
prop("GPIO", serie.gpio),
|
||||
prop("Wi-Fi", serie.wifi),
|
||||
prop("Bluetooth", serie.bluetooth),
|
||||
prop("Zigbee / Thread / 802.15.4", serie.zigbee_thread),
|
||||
prop(isEn ? "Package" : isEs ? "Encapsulado" : isFr ? "Boîtier" : isDe ? "Gehäuse" : "Encapsulamento", serie.encapsulamento),
|
||||
prop(isEn ? "Minimum ESP-IDF" : isEs ? "ESP-IDF mínimo" : isFr ? "ESP-IDF minimum" : isDe ? "Mindestens ESP-IDF" : "ESP-IDF mínimo", serie.esp_idf_minimo),
|
||||
prop(isEn ? "Package" : isEs ? "Encapsulado" : isFr ? "Boîtier" : isZh ? "封装" : isDe ? "Gehäuse" : "Encapsulamento", serie.encapsulamento),
|
||||
prop(isEn ? "Minimum ESP-IDF" : isEs ? "ESP-IDF mínimo" : isFr ? "ESP-IDF minimum" : isZh ? "最低 ESP-IDF 版本" : isDe ? "Mindestens ESP-IDF" : "ESP-IDF mínimo", serie.esp_idf_minimo),
|
||||
].filter(Boolean);
|
||||
|
||||
const imagem = serie.placa
|
||||
? `${SITE.url}${serie.placa}`
|
||||
: `${SITE.url}/opengraph-image.png`;
|
||||
|
||||
const basePath = isDe ? `/de/serien/${chave}` : isFr ? `/fr/series/${chave}` : isEn ? `/en/series/${chave}` : isEs ? `/es/series/${chave}` : `/series/${chave}`;
|
||||
const anchor = isEn ? "article" : isEs ? "articulo" : isFr ? "article" : isDe ? "artikel" : "artigo";
|
||||
const inLang = isEn ? "en" : isEs ? "es-419" : isFr ? "fr" : isDe ? "de" : "pt-BR";
|
||||
const basePath = isZh ? `/zh-CN/series/${chave}` : isDe ? `/de/serien/${chave}` : isFr ? `/fr/series/${chave}` : isEn ? `/en/series/${chave}` : isEs ? `/es/series/${chave}` : `/series/${chave}`;
|
||||
const anchor = isEn ? "article" : isEs ? "articulo" : isFr ? "article" : isZh ? "article" : isDe ? "artikel" : "artigo";
|
||||
const inLang = isEn ? "en" : isEs ? "es-419" : isFr ? "fr" : isZh ? "zh-CN" : isDe ? "de" : "pt-BR";
|
||||
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
@@ -204,7 +206,7 @@ export const jsonLd = {
|
||||
? `${serie.nome_completo || chave}: especificaciones y patillaje`
|
||||
: isFr
|
||||
? `${serie.nome_completo || chave} : spécifications et brochage`
|
||||
: isDe
|
||||
: isZh ? `${serie.nome_completo || chave}:规格与引脚图` : isDe
|
||||
? `${serie.nome_completo || chave}: Spezifikationen und Pinbelegung`
|
||||
: `${serie.nome_completo || chave}: especificações e pinagem`,
|
||||
name: isEn
|
||||
@@ -213,7 +215,7 @@ export const jsonLd = {
|
||||
? `${serie.nome_completo || chave} - Documentación técnica y especificaciones`
|
||||
: isFr
|
||||
? `${serie.nome_completo || chave} - Documentation technique et spécifications`
|
||||
: isDe
|
||||
: isZh ? `${serie.nome_completo || chave} - 技术文档与规格` : isDe
|
||||
? `${serie.nome_completo || chave} - Technische Dokumentation und Spezifikationen`
|
||||
: `${serie.nome_completo || chave} - Documentação Técnica e Especificações`,
|
||||
description: serie.descricao,
|
||||
@@ -254,9 +256,10 @@ export const jsonLd = {
|
||||
const isEs = locale === "es";
|
||||
const isFr = locale === "fr";
|
||||
const isDe = locale === "de";
|
||||
const basePath = isDe ? `/de/frameworks/${encodeURIComponent(chave)}` : isFr ? `/fr/frameworks/${encodeURIComponent(chave)}` : isEn ? `/en/frameworks/${encodeURIComponent(chave)}` : isEs ? `/es/frameworks/${encodeURIComponent(chave)}` : `/frameworks/${encodeURIComponent(chave)}`;
|
||||
const anchor = isEn ? "article" : isEs ? "articulo" : isFr ? "article" : isDe ? "artikel" : "artigo";
|
||||
const inLang = isEn ? "en" : isEs ? "es-419" : isFr ? "fr" : isDe ? "de" : "pt-BR";
|
||||
const isZh = locale === "zh-CN";
|
||||
const basePath = isZh ? `/zh-CN/frameworks/${encodeURIComponent(chave)}` : isDe ? `/de/frameworks/${encodeURIComponent(chave)}` : isFr ? `/fr/frameworks/${encodeURIComponent(chave)}` : isEn ? `/en/frameworks/${encodeURIComponent(chave)}` : isEs ? `/es/frameworks/${encodeURIComponent(chave)}` : `/frameworks/${encodeURIComponent(chave)}`;
|
||||
const anchor = isEn ? "article" : isEs ? "articulo" : isFr ? "article" : isZh ? "article" : isDe ? "artikel" : "artigo";
|
||||
const inLang = isEn ? "en" : isEs ? "es-419" : isFr ? "fr" : isZh ? "zh-CN" : isDe ? "de" : "pt-BR";
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "TechArticle",
|
||||
@@ -267,14 +270,14 @@ export const jsonLd = {
|
||||
? `${framework.nome} para ESP32: Guía y documentación`
|
||||
: isFr
|
||||
? `${framework.nome} pour ESP32 : Guide et documentation`
|
||||
: isDe
|
||||
: isZh ? `用于 ESP32 的 ${framework.nome}:指南与文档` : isDe
|
||||
? `${framework.nome} für ESP32: Leitfaden und Dokumentation`
|
||||
: `${framework.nome} para ESP32: Guia e Documentação`,
|
||||
name: isEn
|
||||
? `${framework.nome_completo || framework.nome} for ESP32`
|
||||
: isFr
|
||||
? `${framework.nome_completo || framework.nome} pour ESP32`
|
||||
: isDe
|
||||
: isZh ? `用于 ESP32 的 ${framework.nome_completo || framework.nome}` : isDe
|
||||
? `${framework.nome_completo || framework.nome} für ESP32`
|
||||
: `${framework.nome_completo || framework.nome} para ESP32`,
|
||||
description: framework.descricao,
|
||||
@@ -317,14 +320,15 @@ export const jsonLd = {
|
||||
const isEs = locale === "es";
|
||||
const isFr = locale === "fr";
|
||||
const isDe = locale === "de";
|
||||
const basePath = isDe ? "/de/glossar" : isFr ? "/fr/glossaire" : isEn ? "/en/glossary" : isEs ? "/es/glosario" : "/glossario";
|
||||
const anchor = isDe ? "glossar" : isFr ? "glossaire" : isEn ? "glossary" : isEs ? "glosario" : "glossario";
|
||||
const inLang = isEn ? "en" : isEs ? "es-419" : isFr ? "fr" : isDe ? "de" : "pt-BR";
|
||||
const isZh = locale === "zh-CN";
|
||||
const basePath = isZh ? "/zh-CN/glossary" : isDe ? "/de/glossar" : isFr ? "/fr/glossaire" : isEn ? "/en/glossary" : isEs ? "/es/glosario" : "/glossario";
|
||||
const anchor = isZh ? "glossary" : isDe ? "glossar" : isFr ? "glossaire" : isEn ? "glossary" : isEs ? "glosario" : "glossario";
|
||||
const inLang = isEn ? "en" : isEs ? "es-419" : isFr ? "fr" : isZh ? "zh-CN" : isDe ? "de" : "pt-BR";
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "DefinedTermSet",
|
||||
"@id": `${SITE.url}${basePath}#${anchor}`,
|
||||
name: isEn ? "ESP32 Technical Glossary" : isEs ? "Glosario técnico de ESP32" : isFr ? "Glossaire technique de l'ESP32" : isDe ? "Technisches Glossar für ESP32" : "Glossário Técnico do ESP32",
|
||||
name: isEn ? "ESP32 Technical Glossary" : isEs ? "Glosario técnico de ESP32" : isFr ? "Glossaire technique de l'ESP32" : isZh ? "ESP32 技术术语表" : isDe ? "Technisches Glossar für ESP32" : "Glossário Técnico do ESP32",
|
||||
inLanguage: inLang,
|
||||
hasDefinedTerm: categorias.flatMap((cat) =>
|
||||
cat.termos.map((t) => ({
|
||||
@@ -356,7 +360,8 @@ export const jsonLd = {
|
||||
const isEs = locale === "es";
|
||||
const isFr = locale === "fr";
|
||||
const isDe = locale === "de";
|
||||
const inLang = isEn ? "en" : isEs ? "es-419" : isFr ? "fr" : isDe ? "de" : "pt-BR";
|
||||
const isZh = locale === "zh-CN";
|
||||
const inLang = isEn ? "en" : isEs ? "es-419" : isFr ? "fr" : isZh ? "zh-CN" : isDe ? "de" : "pt-BR";
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebApplication",
|
||||
@@ -452,21 +457,22 @@ export const jsonLd = {
|
||||
const isEs = locale === "es";
|
||||
const isFr = locale === "fr";
|
||||
const isDe = locale === "de";
|
||||
const basePath = isDe ? "/de/ueber-uns" : isFr ? "/fr/a-propos" : isEn ? "/en/about" : isEs ? "/es/acerca" : "/sobre";
|
||||
const anchor = isDe ? "ueber-uns" : isFr ? "a-propos" : isEn ? "about" : isEs ? "acerca" : "sobre";
|
||||
const inLang = isEn ? "en" : isEs ? "es-419" : isFr ? "fr" : isDe ? "de" : "pt-BR";
|
||||
const isZh = locale === "zh-CN";
|
||||
const basePath = isZh ? "/zh-CN/about" : isDe ? "/de/ueber-uns" : isFr ? "/fr/a-propos" : isEn ? "/en/about" : isEs ? "/es/acerca" : "/sobre";
|
||||
const anchor = isZh ? "about" : isDe ? "ueber-uns" : isFr ? "a-propos" : isEn ? "about" : isEs ? "acerca" : "sobre";
|
||||
const inLang = isEn ? "en" : isEs ? "es-419" : isFr ? "fr" : isZh ? "zh-CN" : isDe ? "de" : "pt-BR";
|
||||
return {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "AboutPage",
|
||||
"@id": `${SITE.url}${basePath}#${anchor}`,
|
||||
name: isEn ? "About ESPDocs" : isEs ? "Acerca de ESPDocs" : isFr ? "À propos d'ESPDocs" : isDe ? "Über ESPDocs" : "Sobre o ESPDocs",
|
||||
name: isEn ? "About ESPDocs" : isEs ? "Acerca de ESPDocs" : isFr ? "À propos d'ESPDocs" : isZh ? "关于 ESPDocs" : isDe ? "Über ESPDocs" : "Sobre o ESPDocs",
|
||||
description: isEn
|
||||
? "ESPDocs is an independent platform organizing technical documentation of the ESP32 ecosystem."
|
||||
: isEs
|
||||
? "ESPDocs es una plataforma independiente que reúne la documentación técnica del ecosistema ESP32."
|
||||
: isFr
|
||||
? "ESPDocs est une plateforme indépendante qui rassemble la documentation technique de l'écosystème ESP32."
|
||||
: isDe
|
||||
: isZh ? "ESPDocs 是一个独立平台,汇集 ESP32 生态的文档,使用简体中文。" : isDe
|
||||
? "ESPDocs ist eine unabhängige Plattform, die die technische Dokumentation des ESP32-Ökosystems zusammenführt."
|
||||
: "O ESPDocs é uma plataforma independente que reúne a documentação do ecossistema ESP32 em português brasileiro.",
|
||||
url: `${SITE.url}${basePath}`,
|
||||
|
||||
Reference in new issue
Block a user