feat(i18n): French and German localization (phase 5)
- Add full message catalogs and content for French (fr) and German (de) - Implement ASCII canonical slugs for French and German routes - Add language-specific search endpoints (/api/busca/fr, /api/busca/de) - Configure strict 404 responses for /fr/livro and /de/livro - Localize SEO, OpenGraph (fr_FR, de_DE), Twitter and JSON-LD schemas - Add localized code example comments across 14 examples for fr and de - Enable 'fr' and 'de' in ENABLED_LOCALES with root negotiation and redirect - Extend test suite in check-i18n, smoke-imagem and verifica-vazamentos Co-Authored-By: Antigravity <noreply@google.com>
This commit is contained in:
1 parent
7b673aeb4b
commit
7fce46b9e1
104 files changed
+33369
-686
No files matched your search
@@ -8,6 +8,8 @@ import { notFound } from "next/navigation";
|
||||
import seriesDataPt from "@/public/series.json";
|
||||
import seriesDataEn from "@/data/en/series.json";
|
||||
import seriesDataEs from "@/data/es/series.json";
|
||||
import seriesDataFr from "@/data/fr/series.json";
|
||||
import seriesDataDe from "@/data/de/series.json";
|
||||
import ConnectionsDiagram from "@/components/ConnectionsDiagram";
|
||||
import SeriesTabMenu from "@/components/SeriesTabMenu";
|
||||
import PinRestrictions from "@/components/PinRestrictions";
|
||||
@@ -37,8 +39,10 @@ export default async function SerieDetail({ params }) {
|
||||
const { locale, key } = await params;
|
||||
const isEn = locale === "en";
|
||||
const isEs = locale === "es";
|
||||
const currentLocale = isEs ? "es" : isEn ? "en" : "pt";
|
||||
const seriesData = isEs ? seriesDataEs : isEn ? seriesDataEn : seriesDataPt;
|
||||
const isFr = locale === "fr";
|
||||
const isDe = locale === "de";
|
||||
const currentLocale = isDe ? "de" : isFr ? "fr" : isEs ? "es" : isEn ? "en" : "pt";
|
||||
const seriesData = isDe ? seriesDataDe : isFr ? seriesDataFr : isEs ? seriesDataEs : isEn ? seriesDataEn : seriesDataPt;
|
||||
const serie = seriesData[key];
|
||||
|
||||
if (!serie) {
|
||||
@@ -47,7 +51,11 @@ export default async function SerieDetail({ params }) {
|
||||
|
||||
let conexoes = [];
|
||||
try {
|
||||
conexoes = isEs
|
||||
conexoes = isDe
|
||||
? require(`@/data/de/conexoes/${key}.json`)
|
||||
: isFr
|
||||
? require(`@/data/fr/conexoes/${key}.json`)
|
||||
: isEs
|
||||
? require(`@/data/es/conexoes/${key}.json`)
|
||||
: isEn
|
||||
? require(`@/data/en/conexoes/${key}.json`)
|
||||
@@ -61,10 +69,26 @@ export default async function SerieDetail({ params }) {
|
||||
const previousKey = currentIndex > 0 ? seriesKeys[currentIndex - 1] : null;
|
||||
const nextKey = currentIndex < seriesKeys.length - 1 ? seriesKeys[currentIndex + 1] : null;
|
||||
|
||||
const nao = isEs || isEn ? "No" : "Não";
|
||||
const naoInformado = isEs ? "No informado" : isEn ? "Not informed" : "Não informado";
|
||||
const nao = isDe ? "Nein" : isFr ? "Non" : isEs || isEn ? "No" : "Não";
|
||||
const naoInformado = isDe ? "Nicht angegeben" : isFr ? "Non communiqué" : isEs ? "No informado" : isEn ? "Not informed" : "Não informado";
|
||||
|
||||
const processadorSpecs = isEs
|
||||
const processadorSpecs = isDe
|
||||
? [
|
||||
{ label: "Architektur", value: serie.arquitetura },
|
||||
{ label: "Kerne", value: serie.nucleos },
|
||||
{ label: "Taktfrequenz", value: serie.frequencia },
|
||||
{ label: "ULP-Coprozessor", value: serie.coprocessador_ulp || nao },
|
||||
{ label: "KI-Beschleuniger", value: serie.aceleradores_ia || nao },
|
||||
]
|
||||
: isFr
|
||||
? [
|
||||
{ label: "Architecture", value: serie.arquitetura },
|
||||
{ label: "Cœurs", value: serie.nucleos },
|
||||
{ label: "Fréquence", value: serie.frequencia },
|
||||
{ label: "Coprocesseur ULP", value: serie.coprocessador_ulp || nao },
|
||||
{ label: "Accélérateurs IA", value: serie.aceleradores_ia || nao },
|
||||
]
|
||||
: isEs
|
||||
? [
|
||||
{ label: "Arquitectura", value: serie.arquitetura },
|
||||
{ label: "Núcleos", value: serie.nucleos },
|
||||
@@ -89,7 +113,37 @@ export default async function SerieDetail({ params }) {
|
||||
];
|
||||
|
||||
const seg = serie.seguranca || {};
|
||||
const segurancaSpecs = isEs
|
||||
const segurancaSpecs = isDe
|
||||
? [
|
||||
{ label: "AES", value: seg.aes || nao },
|
||||
{ label: "SHA", value: seg.sha || nao },
|
||||
{ label: "RSA / MPI", value: seg.rsa || nao },
|
||||
{ label: "ECC (elliptische Kurven)", value: seg.ecc || nao },
|
||||
{ label: "Hardware-ECDSA", value: seg.ecdsa || nao },
|
||||
{ label: "HMAC", value: seg.hmac || nao },
|
||||
{ label: "Digitale Signatur (DS)", value: seg.assinatura_digital || nao },
|
||||
{ label: "Key Manager", value: seg.key_manager || nao },
|
||||
{ label: "Zufallszahlengenerator (TRNG)", value: seg.rng || nao },
|
||||
{ label: "Flash-Verschlüsselung", value: seg.criptografia_flash || nao },
|
||||
{ label: "Secure Boot", value: seg.secure_boot || nao },
|
||||
{ label: "DPA-Schutz", value: seg.protecao_dpa || nao },
|
||||
]
|
||||
: isFr
|
||||
? [
|
||||
{ label: "AES", value: seg.aes || nao },
|
||||
{ label: "SHA", value: seg.sha || nao },
|
||||
{ label: "RSA / MPI", value: seg.rsa || nao },
|
||||
{ label: "ECC (courbes elliptiques)", value: seg.ecc || nao },
|
||||
{ label: "ECDSA matériel", value: seg.ecdsa || nao },
|
||||
{ label: "HMAC", value: seg.hmac || nao },
|
||||
{ label: "Signature numérique (DS)", value: seg.assinatura_digital || nao },
|
||||
{ label: "Key Manager", value: seg.key_manager || nao },
|
||||
{ label: "Générateur aléatoire (TRNG)", value: seg.rng || nao },
|
||||
{ label: "Chiffrement Flash", value: seg.criptografia_flash || nao },
|
||||
{ label: "Secure Boot", value: seg.secure_boot || nao },
|
||||
{ label: "Protection DPA", value: seg.protecao_dpa || nao },
|
||||
]
|
||||
: isEs
|
||||
? [
|
||||
{ label: "AES", value: seg.aes || nao },
|
||||
{ label: "SHA", value: seg.sha || nao },
|
||||
@@ -134,7 +188,23 @@ export default async function SerieDetail({ params }) {
|
||||
{ label: "Proteção contra DPA", value: seg.protecao_dpa || "Não" },
|
||||
];
|
||||
|
||||
const ferramentasSpecs = isEs
|
||||
const ferramentasSpecs = isDe
|
||||
? [
|
||||
{ label: "Minimales ESP-IDF", value: serie.esp_idf_minimo || naoInformado },
|
||||
{ label: "Arduino-Core", value: serie.arduino_core || naoInformado },
|
||||
{ label: "Debugging", value: serie.depuracao || naoInformado },
|
||||
{ label: "Gehäuse", value: serie.encapsulamento || naoInformado },
|
||||
{ label: "Verfügbare Module", value: serie.modulos || naoInformado },
|
||||
]
|
||||
: isFr
|
||||
? [
|
||||
{ label: "ESP-IDF minimal", value: serie.esp_idf_minimo || naoInformado },
|
||||
{ label: "Core Arduino", value: serie.arduino_core || naoInformado },
|
||||
{ label: "Débogage", value: serie.depuracao || naoInformado },
|
||||
{ label: "Boîtier", value: serie.encapsulamento || naoInformado },
|
||||
{ label: "Modules disponibles", value: serie.modulos || naoInformado },
|
||||
]
|
||||
: isEs
|
||||
? [
|
||||
{ label: "ESP-IDF mínimo", value: serie.esp_idf_minimo || naoInformado },
|
||||
{ label: "Core Arduino", value: serie.arduino_core || naoInformado },
|
||||
@@ -158,7 +228,25 @@ export default async function SerieDetail({ params }) {
|
||||
{ label: "Módulos disponíveis", value: serie.modulos || "Não informado" },
|
||||
];
|
||||
|
||||
const conectividadeSpecs = isEs
|
||||
const conectividadeSpecs = isDe
|
||||
? [
|
||||
{ label: "Wi-Fi", value: serie.wifi || nao },
|
||||
{ label: "Bluetooth", value: serie.bluetooth || nao },
|
||||
{ label: "Zigbee/Thread", value: serie.zigbee_thread || nao },
|
||||
{ label: "Matter", value: serie.matter || nao },
|
||||
{ label: "Ethernet", value: serie.ethernet || serie.ethernet_mac || nao },
|
||||
{ label: "CAN", value: serie.can || nao },
|
||||
]
|
||||
: isFr
|
||||
? [
|
||||
{ label: "Wi-Fi", value: serie.wifi || nao },
|
||||
{ label: "Bluetooth", value: serie.bluetooth || nao },
|
||||
{ label: "Zigbee/Thread", value: serie.zigbee_thread || nao },
|
||||
{ label: "Matter", value: serie.matter || nao },
|
||||
{ label: "Ethernet", value: serie.ethernet || serie.ethernet_mac || nao },
|
||||
{ label: "CAN", value: serie.can || nao },
|
||||
]
|
||||
: isEs
|
||||
? [
|
||||
{ label: "Wi-Fi", value: serie.wifi || nao },
|
||||
{ label: "Bluetooth", value: serie.bluetooth || nao },
|
||||
@@ -185,7 +273,23 @@ export default async function SerieDetail({ params }) {
|
||||
{ label: "CAN", value: serie.can || "Não" },
|
||||
];
|
||||
|
||||
const memoriaSpecs = isEs
|
||||
const memoriaSpecs = isDe
|
||||
? [
|
||||
{ label: "SRAM", value: serie.memoria_sram },
|
||||
{ label: "RTC-SRAM", value: serie.memoria_sram_rtc },
|
||||
{ label: "ROM", value: serie.memoria_rom },
|
||||
{ label: "Externer Flash", value: serie.flash_externa },
|
||||
{ label: "Externer PSRAM", value: serie.psram_externa || nao },
|
||||
]
|
||||
: isFr
|
||||
? [
|
||||
{ label: "SRAM", value: serie.memoria_sram },
|
||||
{ label: "SRAM RTC", value: serie.memoria_sram_rtc },
|
||||
{ label: "ROM", value: serie.memoria_rom },
|
||||
{ label: "Flash externe", value: serie.flash_externa },
|
||||
{ label: "PSRAM externe", value: serie.psram_externa || nao },
|
||||
]
|
||||
: isEs
|
||||
? [
|
||||
{ label: "SRAM", value: serie.memoria_sram },
|
||||
{ label: "SRAM RTC", value: serie.memoria_sram_rtc },
|
||||
@@ -209,7 +313,33 @@ export default async function SerieDetail({ params }) {
|
||||
{ label: "PSRAM Externa", value: serie.psram_externa || "Não" },
|
||||
];
|
||||
|
||||
const perifericos = isEs
|
||||
const perifericos = isDe
|
||||
? [
|
||||
{ label: "GPIO", value: serie.gpio },
|
||||
{ label: "ADC", value: serie.adc },
|
||||
{ label: "DAC", value: serie.dac || nao },
|
||||
{ label: "Touch", value: serie.touch || nao },
|
||||
{ label: "UART", value: serie.uart },
|
||||
{ label: "SPI", value: serie.spi },
|
||||
{ label: "I2C", value: serie.i2c },
|
||||
{ label: "I2S", value: serie.i2s },
|
||||
{ label: "PWM", value: serie.pwm },
|
||||
{ label: "USB", value: serie.usb || nao },
|
||||
]
|
||||
: isFr
|
||||
? [
|
||||
{ label: "GPIO", value: serie.gpio },
|
||||
{ label: "ADC", value: serie.adc },
|
||||
{ label: "DAC", value: serie.dac || nao },
|
||||
{ label: "Touch", value: serie.touch || nao },
|
||||
{ label: "UART", value: serie.uart },
|
||||
{ label: "SPI", value: serie.spi },
|
||||
{ label: "I2C", value: serie.i2c },
|
||||
{ label: "I2S", value: serie.i2s },
|
||||
{ label: "PWM", value: serie.pwm },
|
||||
{ label: "USB", value: serie.usb || nao },
|
||||
]
|
||||
: isEs
|
||||
? [
|
||||
{ label: "GPIO", value: serie.gpio },
|
||||
{ label: "ADC", value: serie.adc },
|
||||
@@ -250,12 +380,12 @@ export default async function SerieDetail({ params }) {
|
||||
|
||||
const interfacesEspeciais = [];
|
||||
if (serie.lcd) interfacesEspeciais.push({ label: "LCD", value: serie.lcd });
|
||||
if (serie.camera) interfacesEspeciais.push({ label: isEs ? "Cámara" : isEn ? "Camera" : "Câmera", value: serie.camera });
|
||||
if (serie.camera) interfacesEspeciais.push({ label: isDe ? "Kamera" : isFr ? "Caméra" : isEs ? "Cámara" : isEn ? "Camera" : "Câmera", value: serie.camera });
|
||||
if (serie.mipi_csi) interfacesEspeciais.push({ label: "MIPI CSI", value: serie.mipi_csi });
|
||||
if (serie.mipi_dsi) interfacesEspeciais.push({ label: "MIPI DSI", value: serie.mipi_dsi });
|
||||
if (serie.sdio) interfacesEspeciais.push({ label: "SDIO", value: serie.sdio });
|
||||
if (serie.sensor_hall) interfacesEspeciais.push({ label: isEs ? "Sensor Hall" : isEn ? "Hall Sensor" : "Sensor Hall", value: serie.sensor_hall });
|
||||
if (serie.sensor_temperatura) interfacesEspeciais.push({ label: isEs ? "Sensor de temperatura" : isEn ? "Temperature Sensor" : "Sensor Temperatura", value: serie.sensor_temperatura });
|
||||
if (serie.sensor_hall) interfacesEspeciais.push({ label: isDe ? "Hall-Sensor" : isFr ? "Capteur Hall" : isEs ? "Sensor Hall" : isEn ? "Hall Sensor" : "Sensor Hall", value: serie.sensor_hall });
|
||||
if (serie.sensor_temperatura) interfacesEspeciais.push({ label: isDe ? "Temperatursensor" : isFr ? "Capteur de température" : isEs ? "Sensor de temperatura" : isEn ? "Temperature Sensor" : "Sensor Temperatura", value: serie.sensor_temperatura });
|
||||
|
||||
// Consumo de Energia
|
||||
const consumoEnergia = [];
|
||||
@@ -302,7 +432,35 @@ export default async function SerieDetail({ params }) {
|
||||
'deep_sleep': 'Deep Sleep',
|
||||
'hibernation': 'Hibernación'
|
||||
};
|
||||
const modoLabels = isEs ? modoLabelsEs : isEn ? modoLabelsEn : modoLabelsPt;
|
||||
const modoLabelsFr = {
|
||||
'active': 'Mode actif',
|
||||
'active_cpu_240mhz': 'Actif (CPU 240MHz)',
|
||||
'active_cpu_160mhz': 'Actif (CPU 160MHz)',
|
||||
'active_wifi_tx': 'Actif (Wi-Fi TX)',
|
||||
'active_wifi_tx_peak': 'Actif (Wi-Fi TX Pic)',
|
||||
'active_wifi': 'Actif (Wi-Fi)',
|
||||
'active_wifi6': 'Actif (Wi-Fi 6)',
|
||||
'modem_sleep': 'Modem Sleep',
|
||||
'modem_sleep_cpu_160mhz': 'Modem Sleep (CPU 160MHz)',
|
||||
'light_sleep': 'Light Sleep',
|
||||
'deep_sleep': 'Deep Sleep',
|
||||
'hibernation': 'Hibernation'
|
||||
};
|
||||
const modoLabelsDe = {
|
||||
'active': 'Aktivmodus',
|
||||
'active_cpu_240mhz': 'Aktiv (CPU 240MHz)',
|
||||
'active_cpu_160mhz': 'Aktiv (CPU 160MHz)',
|
||||
'active_wifi_tx': 'Aktiv (Wi-Fi TX)',
|
||||
'active_wifi_tx_peak': 'Aktiv (Wi-Fi TX Spitze)',
|
||||
'active_wifi': 'Aktiv (Wi-Fi)',
|
||||
'active_wifi6': 'Aktiv (Wi-Fi 6)',
|
||||
'modem_sleep': 'Modem Sleep',
|
||||
'modem_sleep_cpu_160mhz': 'Modem Sleep (CPU 160MHz)',
|
||||
'light_sleep': 'Light Sleep',
|
||||
'deep_sleep': 'Deep Sleep',
|
||||
'hibernation': 'Ruhezustand'
|
||||
};
|
||||
const modoLabels = isDe ? modoLabelsDe : isFr ? modoLabelsFr : isEs ? modoLabelsEs : isEn ? modoLabelsEn : modoLabelsPt;
|
||||
|
||||
Object.entries(serie.consumo_energia).forEach(([modo, consumo]) => {
|
||||
consumoEnergia.push({
|
||||
@@ -315,17 +473,17 @@ export default async function SerieDetail({ params }) {
|
||||
const tabs = [
|
||||
{
|
||||
id: "devboard",
|
||||
label: isEs ? "Placa de desarrollo" : isEn ? "Development board" : "Placa de desenvolvimento",
|
||||
label: isDe ? "Entwicklungsboard" : isFr ? "Carte de développement" : isEs ? "Placa de desarrollo" : isEn ? "Development board" : "Placa de desenvolvimento",
|
||||
available: serie.placa,
|
||||
content: (
|
||||
<div className="card p-5 sm:p-7">
|
||||
<h2 className="text-lg font-semibold text-ink">
|
||||
{isEs ? "Kit de desarrollo oficial" : isEn ? "Official development kit" : "Kit de desenvolvimento oficial"}
|
||||
{isDe ? "Offizielles Development Kit" : isFr ? "Kit de développement officiel" : isEs ? "Kit de desarrollo oficial" : isEn ? "Official development kit" : "Kit de desenvolvimento oficial"}
|
||||
</h2>
|
||||
<div className="mt-5 overflow-hidden rounded-xl border border-line bg-surface-2 p-4">
|
||||
<Image
|
||||
src={serie.placa}
|
||||
alt={isEs ? `Placa de desarrollo ${key}` : isEn ? `Development board ${key}` : `Placa de desenvolvimento ${key}`}
|
||||
alt={isDe ? `Entwicklungsboard ${key}` : isFr ? `Carte de développement ${key}` : isEs ? `Placa de desarrollo ${key}` : isEn ? `Development board ${key}` : `Placa de desenvolvimento ${key}`}
|
||||
width={1200}
|
||||
height={800}
|
||||
className="mx-auto h-auto max-h-[28rem] w-full rounded-lg object-contain"
|
||||
@@ -333,7 +491,11 @@ export default async function SerieDetail({ params }) {
|
||||
/>
|
||||
</div>
|
||||
<p className="mt-3 text-sm text-muted">
|
||||
{isEs ? (
|
||||
{isDe ? (
|
||||
<>Offizielles Espressif-Board für die Serie {key}.</>
|
||||
) : isFr ? (
|
||||
<>Carte officielle d'Espressif pour la série {key}.</>
|
||||
) : isEs ? (
|
||||
<>Placa estándar de Espressif para la serie {key}.</>
|
||||
) : isEn ? (
|
||||
<>Official Espressif board for the {key} series.</>
|
||||
@@ -346,7 +508,7 @@ export default async function SerieDetail({ params }) {
|
||||
},
|
||||
{
|
||||
id: "connections",
|
||||
label: isEs ? "Diagrama de patillaje" : isEn ? "Pinout diagram" : "Diagrama de conexões",
|
||||
label: isDe ? "Pinbelegungsdiagramm" : isFr ? "Diagramme de brochage" : isEs ? "Diagrama de patillaje" : isEn ? "Pinout diagram" : "Diagrama de conexões",
|
||||
available: conexoes.length > 0,
|
||||
content: (
|
||||
<div className="card p-5 sm:p-7">
|
||||
@@ -354,10 +516,14 @@ export default async function SerieDetail({ params }) {
|
||||
<AlertTriangle className="mt-0.5 h-5 w-5 shrink-0 text-gold" aria-hidden="true" />
|
||||
<div>
|
||||
<p className="font-semibold text-ink">
|
||||
{isEs ? "Este es el diagrama del chip, no de la placa" : isEn ? "This is the chip diagram, not the development board" : "Este é o diagrama do chip, não da placa"}
|
||||
{isDe ? "Dies ist das Diagramm des Chips, nicht des Entwicklungsboards" : isFr ? "Ceci est le schéma de la puce, pas de la carte de développement" : isEs ? "Este es el diagrama del chip, no de la placa" : isEn ? "This is the chip diagram, not the development board" : "Este é o diagrama do chip, não da placa"}
|
||||
</p>
|
||||
<p className="mt-1">
|
||||
{isEs ? (
|
||||
{isDe ? (
|
||||
`Das Diagramm zeigt die Silizium-Anschlüsse des ${key}. Jedes Entwicklungsboard führt nur einen Teil heraus oder leitet sie anders weiter.`
|
||||
) : isFr ? (
|
||||
`Le schéma montre les connexions du silicium du ${key}. Chaque carte de développement n'en expose qu'une partie ou les route différemment.`
|
||||
) : isEs ? (
|
||||
`El mapa muestra las conexiones del silicio del ${key}. Cada placa de desarrollo expone solo parte de ellas o las enruta de otra forma.`
|
||||
) : isEn ? (
|
||||
`The map shows the silicon connections for the ${key}. Each development board exposes only a subset or routes them differently.`
|
||||
@@ -378,10 +544,41 @@ export default async function SerieDetail({ params }) {
|
||||
<div className="callout mt-8">
|
||||
<p className="flex items-center gap-2 font-semibold text-ink">
|
||||
<Lightbulb className="h-4 w-4 text-accent" aria-hidden="true" />
|
||||
{isEs ? "Casi todos los pines son reconfigurables" : isEn ? "Almost every pin is reconfigurable" : "Quase todo pino é reconfigurável"}
|
||||
{isDe ? "Nahezu jeder Pin ist rekonfigurierbar" : isFr ? "La quasi-totalité des broches est reconfigurable" : isEs ? "Casi todos los pines son reconfigurables" : isEn ? "Almost every pin is reconfigurable" : "Quase todo pino é reconfigurável"}
|
||||
</p>
|
||||
<p className="mt-1">
|
||||
{isEs ? (
|
||||
{isDe ? (
|
||||
<>
|
||||
Die IO-Matrix des {key} ermöglicht das Zuweisen von SPI, I2C, UART, PWM und Kamera-/Displaybussen
|
||||
zu den meisten digitalen Pins. Für Strapping-Einschränkungen und analoge Pins konsultieren Sie den{" "}
|
||||
<a
|
||||
href={`https://docs.espressif.com/projects/esp-idf/en/latest/${String(key).toLowerCase().replace("-", "")}/api-reference/peripherals/gpio.html`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-1 font-medium text-accent underline decoration-accent/30 underline-offset-2 hover:decoration-accent"
|
||||
>
|
||||
offiziellen GPIO-Leitfaden
|
||||
<ExternalLink className="h-3.5 w-3.5" aria-hidden="true" />
|
||||
</a>
|
||||
.
|
||||
</>
|
||||
) : isFr ? (
|
||||
<>
|
||||
La matrice d'E/S du {key} permet d'assigner SPI, I2C, UART, PWM et bus caméra/écran
|
||||
à la majorité des broches numériques. Pour les restrictions de strapping et broches analogiques,
|
||||
consultez le{" "}
|
||||
<a
|
||||
href={`https://docs.espressif.com/projects/esp-idf/en/latest/${String(key).toLowerCase().replace("-", "")}/api-reference/peripherals/gpio.html`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-1 font-medium text-accent underline decoration-accent/30 underline-offset-2 hover:decoration-accent"
|
||||
>
|
||||
guide officiel GPIO
|
||||
<ExternalLink className="h-3.5 w-3.5" aria-hidden="true" />
|
||||
</a>
|
||||
.
|
||||
</>
|
||||
) : isEs ? (
|
||||
<>
|
||||
La matriz de E/S del {key} permite mover buses SPI, I2C, UART, PWM y cámara/pantalla
|
||||
a la mayoría de los pines digitales. Para las restricciones de strapping y pines analógicos,
|
||||
@@ -437,44 +634,48 @@ export default async function SerieDetail({ params }) {
|
||||
];
|
||||
|
||||
const secoes = [
|
||||
{ id: "processador", titulo: isEs ? "Procesador" : isEn ? "Processor" : "Processador", icon: Cpu, specs: processadorSpecs },
|
||||
{ id: "conectividade", titulo: isEs ? "Conectividad" : isEn ? "Connectivity" : "Conectividade", icon: Wifi, specs: conectividadeSpecs },
|
||||
{ id: "ferramentas", titulo: isEs ? "Herramientas y disponibilidad" : isEn ? "Tools and availability" : "Ferramentas e disponibilidade", icon: Package, specs: ferramentasSpecs },
|
||||
{ id: "seguranca", titulo: isEs ? "Seguridad" : isEn ? "Security" : "Segurança", icon: ShieldCheck, specs: segurancaSpecs },
|
||||
{ id: "memoria", titulo: isEs ? "Memoria" : isEn ? "Memory" : "Memória", icon: Database, specs: memoriaSpecs },
|
||||
{ id: "processador", titulo: isDe ? "Prozessor" : isFr ? "Processeur" : isEs ? "Procesador" : isEn ? "Processor" : "Processador", icon: Cpu, specs: processadorSpecs },
|
||||
{ id: "conectividade", titulo: isDe ? "Konnektivität" : isFr ? "Connectivité" : isEs ? "Conectividad" : isEn ? "Connectivity" : "Conectividade", icon: Wifi, specs: conectividadeSpecs },
|
||||
{ id: "ferramentas", titulo: isDe ? "Werkzeuge und Verfügbarkeit" : isFr ? "Outils et disponibilité" : isEs ? "Herramientas y disponibilidad" : isEn ? "Tools and availability" : "Ferramentas e disponibilidade", icon: Package, specs: ferramentasSpecs },
|
||||
{ id: "seguranca", titulo: isDe ? "Sicherheit" : isFr ? "Sécurité" : isEs ? "Seguridad" : isEn ? "Security" : "Segurança", icon: ShieldCheck, specs: segurancaSpecs },
|
||||
{ id: "memoria", titulo: isDe ? "Speicher" : isFr ? "Mémoire" : isEs ? "Memoria" : isEn ? "Memory" : "Memória", icon: Database, specs: memoriaSpecs },
|
||||
...(consumoEnergia.length > 0
|
||||
? [{
|
||||
id: "energia",
|
||||
titulo: isEs ? "Consumo de energía" : isEn ? "Power consumption" : "Consumo de energia",
|
||||
titulo: isDe ? "Stromverbrauch" : isFr ? "Consommation d'énergie" : isEs ? "Consumo de energía" : isEn ? "Power consumption" : "Consumo de energia",
|
||||
icon: Battery,
|
||||
specs: consumoEnergia,
|
||||
nota: isEs
|
||||
nota: isDe
|
||||
? "Typische Werte bei 3,3 V und 25 °C. Der tatsächliche Stromverbrauch hängt vom Funk-Tastgrad und der konfigurierten Taktfrequenz ab."
|
||||
: isFr
|
||||
? "Valeurs typiques à 3,3 V et 25 °C. La consommation réelle dépend du cycle de travail de la radio et de la fréquence d'horloge configurée."
|
||||
: isEs
|
||||
? "Valores típicos a 3,3 V y 25 °C. El consumo real depende del ciclo de trabajo de la radio y de la frecuencia de reloj configurada."
|
||||
: isEn
|
||||
? "Typical values at 3.3 V and 25 °C. Actual power consumption depends on radio duty cycle and configured clock frequency."
|
||||
: "Valores típicos a 3,3 V e 25 °C. O consumo real depende do ciclo de trabalho do rádio e da frequência de clock configurada.",
|
||||
}]
|
||||
: []),
|
||||
{ id: "perifericos", titulo: isEs ? "Periféricos" : isEn ? "Peripherals" : "Periféricos", icon: Sliders, specs: perifericos },
|
||||
{ id: "perifericos", titulo: isDe ? "Peripherie" : isFr ? "Périphériques" : isEs ? "Periféricos" : isEn ? "Peripherals" : "Periféricos", icon: Sliders, specs: perifericos },
|
||||
...(interfacesEspeciais.length > 0
|
||||
? [{ id: "interfaces", titulo: isEs ? "Interfaces especiales" : isEn ? "Special interfaces" : "Interfaces especiais", icon: Sliders, specs: interfacesEspeciais }]
|
||||
? [{ id: "interfaces", titulo: isDe ? "Spezielle Schnittstellen" : isFr ? "Interfaces spéciales" : isEs ? "Interfaces especiales" : isEn ? "Special interfaces" : "Interfaces especiais", icon: Sliders, specs: interfacesEspeciais }]
|
||||
: []),
|
||||
{
|
||||
id: "temperatura",
|
||||
titulo: isEs ? "Límites de temperatura" : isEn ? "Temperature limits" : "Limites de temperatura",
|
||||
titulo: isDe ? "Temperaturgrenzwerte" : isFr ? "Limites de température" : isEs ? "Límites de temperatura" : isEn ? "Temperature limits" : "Limites de temperatura",
|
||||
icon: Thermometer,
|
||||
specs: [
|
||||
{ label: isEs ? "Operación" : isEn ? "Operating" : "Operação", value: serie.temperatura_operacao },
|
||||
{ label: isEs ? "Almacenamiento" : isEn ? "Storage" : "Armazenamento", value: serie.temperatura_armazenamento },
|
||||
{ label: isDe ? "Betrieb" : isFr ? "Fonctionnement" : isEs ? "Operación" : isEn ? "Operating" : "Operação", value: serie.temperatura_operacao },
|
||||
{ label: isDe ? "Lagerung" : isFr ? "Stockage" : isEs ? "Almacenamiento" : isEn ? "Storage" : "Armazenamento", value: serie.temperatura_armazenamento },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const fatos = [
|
||||
{ label: isEs ? "Procesador" : isEn ? "Processor" : "Processador", value: String(serie.nucleos).includes("2") ? "Dual-core" : "Single-core", detail: serie.frequencia },
|
||||
{ label: "SRAM", value: serie.memoria_sram, detail: isEs ? `+ ${serie.memoria_sram_rtc} de SRAM RTC` : isEn ? `+ ${serie.memoria_sram_rtc} RTC SRAM` : `+ ${serie.memoria_sram_rtc} de SRAM RTC` },
|
||||
{ label: "GPIO", value: serie.gpio, detail: isEs ? "pines programables" : isEn ? "programmable pins" : "pinos programáveis" },
|
||||
{ label: isEs ? "Arquitectura" : isEn ? "Architecture" : "Arquitetura", value: String(serie.arquitetura).includes("RISC-V") ? "RISC-V" : "Xtensa", detail: serie.arquitetura },
|
||||
{ label: isDe ? "Prozessor" : isFr ? "Processeur" : isEs ? "Procesador" : isEn ? "Processor" : "Processador", value: String(serie.nucleos).includes("2") ? "Dual-core" : "Single-core", detail: serie.frequencia },
|
||||
{ label: "SRAM", value: serie.memoria_sram, detail: isDe ? `+ ${serie.memoria_sram_rtc} RTC-SRAM` : isFr ? `+ ${serie.memoria_sram_rtc} de SRAM RTC` : isEs ? `+ ${serie.memoria_sram_rtc} de SRAM RTC` : isEn ? `+ ${serie.memoria_sram_rtc} RTC SRAM` : `+ ${serie.memoria_sram_rtc} de SRAM RTC` },
|
||||
{ label: "GPIO", value: serie.gpio, detail: isDe ? "programmierbare Pins" : isFr ? "broches programmables" : isEs ? "pines programables" : isEn ? "programmable pins" : "pinos programáveis" },
|
||||
{ label: isDe ? "Architektur" : isFr ? "Architecture" : isEs ? "Arquitectura" : isEn ? "Architecture" : "Arquitetura", value: String(serie.arquitetura).includes("RISC-V") ? "RISC-V" : "Xtensa", detail: serie.arquitetura },
|
||||
];
|
||||
|
||||
return (
|
||||
@@ -487,8 +688,8 @@ export default async function SerieDetail({ params }) {
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: JSON.stringify(jsonLd.trilha([
|
||||
{ nome: isEs ? "Inicio" : isEn ? "Home" : "Início", caminho: isEn ? "/en" : isEs ? "/es" : "/" },
|
||||
{ nome: isEs ? "Series" : isEn ? "Series" : "Séries", caminho: getLocalizedHref("/series", currentLocale) },
|
||||
{ nome: isDe ? "Startseite" : isFr ? "Accueil" : isEs ? "Inicio" : isEn ? "Home" : "Início", caminho: isDe ? "/de" : isFr ? "/fr" : isEn ? "/en" : isEs ? "/es" : "/" },
|
||||
{ nome: isDe ? "ESP32-Serien" : isFr ? "Séries ESP32" : isEs ? "Series ESP32" : isEn ? "ESP32 Series" : "Séries ESP32", caminho: getLocalizedHref("/series", currentLocale) },
|
||||
{ nome: serie.nome_completo, caminho: getLocalizedHref(`/series/${key}`, currentLocale) },
|
||||
])),
|
||||
}}
|
||||
@@ -500,7 +701,9 @@ export default async function SerieDetail({ params }) {
|
||||
<PageHero
|
||||
isEn={isEn}
|
||||
isEs={isEs}
|
||||
trail={[{ label: isEs ? "Series" : isEn ? "Series" : "Séries", href: getLocalizedHref("/series", currentLocale) }, { label: key }]}
|
||||
isFr={isFr}
|
||||
isDe={isDe}
|
||||
trail={[{ label: isDe ? "Serien" : isFr ? "Séries" : isEs ? "Series" : isEn ? "Series" : "Séries", href: getLocalizedHref("/series", currentLocale) }, { label: key }]}
|
||||
icon={Cpu}
|
||||
label={serie.arquitetura}
|
||||
title={key}
|
||||
@@ -509,32 +712,32 @@ export default async function SerieDetail({ params }) {
|
||||
{serie.datasheet ? (
|
||||
<a href={serie.datasheet} target="_blank" rel="noopener noreferrer" className="btn btn-primary">
|
||||
<FileText className="h-4 w-4" aria-hidden="true" />
|
||||
{isEs ? "Datasheet oficial" : isEn ? "Official datasheet" : "Datasheet oficial"}
|
||||
{isDe ? "Offizielles Datenblatt" : isFr ? "Datasheet officiel" : isEs ? "Datasheet oficial" : isEn ? "Official datasheet" : "Datasheet oficial"}
|
||||
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
|
||||
</a>
|
||||
) : (
|
||||
<span className="btn btn-ghost cursor-not-allowed opacity-70" aria-disabled="true">
|
||||
<FileText className="h-4 w-4" aria-hidden="true" />
|
||||
{isEs ? "Datasheet aún no publicado" : isEn ? "Datasheet not yet published" : "Datasheet ainda não publicado"}
|
||||
{isDe ? "Datenblatt noch nicht veröffentlicht" : isFr ? "Datasheet pas encore publié" : isEs ? "Datasheet aún no publicado" : isEn ? "Datasheet not yet published" : "Datasheet ainda não publicado"}
|
||||
</span>
|
||||
)}
|
||||
{serie.guia_de_programacao && (
|
||||
<a href={serie.guia_de_programacao} target="_blank" rel="noopener noreferrer" className="btn btn-ghost">
|
||||
<Code className="h-4 w-4" aria-hidden="true" />
|
||||
{isEs ? "Guía de programación" : isEn ? "Programming guide" : "Guia de programação"}
|
||||
{isDe ? "Programmierleitfaden" : isFr ? "Guide de programmation" : isEs ? "Guía de programación" : isEn ? "Programming guide" : "Guia de programação"}
|
||||
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
|
||||
</a>
|
||||
)}
|
||||
{serie.manual_tecnico && (
|
||||
<a href={serie.manual_tecnico} target="_blank" rel="noopener noreferrer" className="btn btn-ghost">
|
||||
<BookOpen className="h-4 w-4" aria-hidden="true" />
|
||||
{isEs ? "Manual de referencia técnica" : isEn ? "Technical reference manual" : "Manual técnico"}
|
||||
{isDe ? "Technisches Referenzhandbuch" : isFr ? "Manuel technique de référence" : isEs ? "Manual de referencia técnica" : isEn ? "Technical reference manual" : "Manual técnico"}
|
||||
<ArrowUpRight className="h-4 w-4" aria-hidden="true" />
|
||||
</a>
|
||||
)}
|
||||
</PageHero>
|
||||
|
||||
<section className="shell mt-10" aria-label={isEs ? "Resumen" : isEn ? "Summary" : "Resumo"}>
|
||||
<section className="shell mt-10" aria-label={isDe ? "Zusammenfassung" : isFr ? "Résumé" : isEs ? "Resumen" : isEn ? "Summary" : "Resumo"}>
|
||||
<dl className="grid grid-cols-2 gap-3 lg:grid-cols-4">
|
||||
{fatos.map((fato) => (
|
||||
<div key={fato.label} className="tile">
|
||||
@@ -550,7 +753,7 @@ export default async function SerieDetail({ params }) {
|
||||
<AlertTriangle className="mt-0.5 h-5 w-5 shrink-0 text-gold" aria-hidden="true" />
|
||||
<div>
|
||||
<p className="font-semibold text-ink">
|
||||
{isEs ? "Documentación preliminar" : isEn ? "Preliminary documentation" : "Documentação preliminar"}
|
||||
{isDe ? "Vorläufige Dokumentation" : isFr ? "Documentation préliminaire" : isEs ? "Documentación preliminar" : isEn ? "Preliminary documentation" : "Documentação preliminar"}
|
||||
</p>
|
||||
<p className="mt-1">{serie.status_documentacao}</p>
|
||||
</div>
|
||||
@@ -559,13 +762,13 @@ export default async function SerieDetail({ params }) {
|
||||
</section>
|
||||
|
||||
<div className="shell mt-10">
|
||||
<SeriesTabMenu tabs={tabs} isEn={isEn} isEs={isEs} />
|
||||
<PinRestrictions conexoes={conexoes} serieKey={key} isEn={isEn} isEs={isEs} />
|
||||
<SeriesTabMenu tabs={tabs} isEn={isEn} isEs={isEs} isFr={isFr} isDe={isDe} />
|
||||
<PinRestrictions conexoes={conexoes} serieKey={key} isEn={isEn} isEs={isEs} isFr={isFr} isDe={isDe} />
|
||||
</div>
|
||||
|
||||
<div className="shell mt-12">
|
||||
<nav
|
||||
aria-label={isEs ? "Secciones de la ficha" : isEn ? "Datasheet sections" : "Seções da ficha"}
|
||||
aria-label={isDe ? "Abschnitte des Datenblatts" : isFr ? "Sections de la fiche" : isEs ? "Secciones de la ficha" : isEn ? "Datasheet sections" : "Seções da ficha"}
|
||||
className="nav-pill no-scrollbar sticky top-20 z-30 flex gap-1 overflow-x-auto rounded-full p-1.5"
|
||||
>
|
||||
{secoes.map((secao) => (
|
||||
@@ -586,7 +789,11 @@ export default async function SerieDetail({ params }) {
|
||||
<div className="panel flex flex-col items-start justify-between gap-6 p-7 sm:p-10 md:flex-row md:items-center">
|
||||
<div className="max-w-2xl">
|
||||
<h2 className="section-title">
|
||||
{isEs ? (
|
||||
{isDe ? (
|
||||
<>Bereit zum Prototyping mit {key}?</>
|
||||
) : isFr ? (
|
||||
<>Prêt à prototyper avec {key} ?</>
|
||||
) : isEs ? (
|
||||
<>¿Listo para prototipar con {key}?</>
|
||||
) : isEn ? (
|
||||
<>Ready to prototype with {key}?</>
|
||||
@@ -595,7 +802,11 @@ export default async function SerieDetail({ params }) {
|
||||
)}
|
||||
</h2>
|
||||
<p className="mt-3 text-base text-muted">
|
||||
{isEs
|
||||
{isDe
|
||||
? "Entdecken Sie die für diese Serie verfügbaren Entwicklungsboards mit USB, integrierten Sensoren und Links zum offiziellen Shop."
|
||||
: isFr
|
||||
? "Explorez les cartes de développement disponibles pour cette série, avec USB, capteurs intégrés et liens vers la boutique officielle."
|
||||
: isEs
|
||||
? "Explore las placas de desarrollo disponibles para esta serie, con USB, sensores integrados y enlaces a la tienda oficial."
|
||||
: isEn
|
||||
? "Explore development boards available for this series, with USB, onboard sensors, and official store links."
|
||||
@@ -603,17 +814,17 @@ export default async function SerieDetail({ params }) {
|
||||
</p>
|
||||
</div>
|
||||
<Link href={getLocalizedHref("/catalogo", currentLocale)} className="btn btn-primary shrink-0">
|
||||
{isEs ? "Ver placas" : isEn ? "View boards" : "Ver placas"}
|
||||
{isDe ? "Boards ansehen" : isFr ? "Voir les cartes" : isEs ? "Ver placas" : isEn ? "View boards" : "Ver placas"}
|
||||
<ArrowRight className="h-4 w-4" aria-hidden="true" />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<nav aria-label={isEs ? "Otras series" : isEn ? "Other series" : "Outras séries"} className="mt-6 grid gap-3 sm:grid-cols-[1fr_auto_1fr] sm:items-center">
|
||||
<nav aria-label={isDe ? "Andere Serien" : isFr ? "Autres séries" : isEs ? "Otras series" : isEn ? "Other series" : "Outras séries"} className="mt-6 grid gap-3 sm:grid-cols-[1fr_auto_1fr] sm:items-center">
|
||||
{previousKey ? (
|
||||
<Link href={getLocalizedHref(`/series/${previousKey}`, currentLocale)} className="card card-interactive group flex items-center gap-3 px-5 py-4">
|
||||
<ArrowLeft className="h-4 w-4 text-muted transition-transform group-hover:-translate-x-1" aria-hidden="true" />
|
||||
<span>
|
||||
<span className="block text-xs text-muted">{isEs ? "Serie anterior" : isEn ? "Previous series" : "Série anterior"}</span>
|
||||
<span className="block text-xs text-muted">{isDe ? "Vorherige Serie" : isFr ? "Série précédente" : isEs ? "Serie anterior" : isEn ? "Previous series" : "Série anterior"}</span>
|
||||
<span className="block font-display text-lg font-semibold text-ink">{previousKey}</span>
|
||||
</span>
|
||||
</Link>
|
||||
@@ -622,12 +833,12 @@ export default async function SerieDetail({ params }) {
|
||||
)}
|
||||
<Link href={getLocalizedHref("/comparacao", currentLocale)} className="btn btn-ghost justify-self-center">
|
||||
<Scale className="h-4 w-4" aria-hidden="true" />
|
||||
{isEs ? "Comparar series" : isEn ? "Compare series" : "Comparar séries"}
|
||||
{isDe ? "Serien vergleichen" : isFr ? "Comparer les séries" : isEs ? "Comparar series" : isEn ? "Compare series" : "Comparar séries"}
|
||||
</Link>
|
||||
{nextKey ? (
|
||||
<Link href={getLocalizedHref(`/series/${nextKey}`, currentLocale)} className="card card-interactive group flex items-center justify-end gap-3 px-5 py-4 text-right">
|
||||
<span>
|
||||
<span className="block text-xs text-muted">{isEs ? "Siguiente serie" : isEn ? "Next series" : "Próxima série"}</span>
|
||||
<span className="block text-xs text-muted">{isDe ? "Nächste Serie" : isFr ? "Série suivante" : isEs ? "Siguiente serie" : isEn ? "Next series" : "Próxima série"}</span>
|
||||
<span className="block font-display text-lg font-semibold text-ink">{nextKey}</span>
|
||||
</span>
|
||||
<ArrowRight className="h-4 w-4 text-muted transition-transform group-hover:translate-x-1" aria-hidden="true" />
|
||||
@@ -673,12 +884,25 @@ export async function generateMetadata({ params }) {
|
||||
const { locale, key } = await params;
|
||||
const isEn = locale === "en";
|
||||
const isEs = locale === "es";
|
||||
const currentLocale = isEs ? "es" : isEn ? "en" : "pt";
|
||||
const seriesData = isEs ? seriesDataEs : isEn ? seriesDataEn : seriesDataPt;
|
||||
const isFr = locale === "fr";
|
||||
const isDe = locale === "de";
|
||||
const currentLocale = isDe ? "de" : isFr ? "fr" : isEs ? "es" : isEn ? "en" : "pt";
|
||||
const seriesData = isDe ? seriesDataDe : isFr ? seriesDataFr : isEs ? seriesDataEs : isEn ? seriesDataEn : seriesDataPt;
|
||||
const serie = seriesData[key];
|
||||
|
||||
if (!serie) {
|
||||
return { title: isEs ? "Serie no encontrada" : isEn ? "Series not found" : "Série não encontrada", robots: { index: false, follow: false } };
|
||||
return {
|
||||
title: isDe
|
||||
? "Serie nicht gefunden"
|
||||
: isFr
|
||||
? "Série non trouvée"
|
||||
: isEs
|
||||
? "Serie no encontrada"
|
||||
: isEn
|
||||
? "Series not found"
|
||||
: "Série não encontrada",
|
||||
robots: { index: false, follow: false },
|
||||
};
|
||||
}
|
||||
|
||||
const radio = [
|
||||
@@ -687,7 +911,17 @@ export async function generateMetadata({ params }) {
|
||||
serie.zigbee_thread && !String(serie.zigbee_thread).startsWith("Não") && !String(serie.zigbee_thread).startsWith("No") ? "802.15.4" : null,
|
||||
].filter(Boolean).join(", ");
|
||||
|
||||
const descricao = isEs
|
||||
const descricao = isDe
|
||||
? `${serie.nome_completo}: ${serie.arquitetura}, ${serie.frequencia}, ` +
|
||||
`${serie.memoria_sram} SRAM und ${serie.gpio} GPIOs` +
|
||||
(radio ? `. Funk: ${radio}` : "") +
|
||||
`. Vollständige Pinbelegung, Peripherie, Hardwaresicherheit und eingeschränkte Pins auf Deutsch.`
|
||||
: isFr
|
||||
? `${serie.nome_completo} : ${serie.arquitetura}, ${serie.frequencia}, ` +
|
||||
`${serie.memoria_sram} de SRAM et ${serie.gpio} GPIO` +
|
||||
(radio ? `. Radio : ${radio}` : "") +
|
||||
`. Brochage complet, périphériques, sécurité matérielle et broches avec restrictions, en français.`
|
||||
: isEs
|
||||
? `${serie.nome_completo}: ${serie.arquitetura}, ${serie.frequencia}, ` +
|
||||
`${serie.memoria_sram} de SRAM y ${serie.gpio} GPIO` +
|
||||
(radio ? `. Radio: ${radio}` : "") +
|
||||
@@ -703,10 +937,22 @@ export async function generateMetadata({ params }) {
|
||||
`. Pinagem completa, periféricos, segurança em hardware e pinos com restrição, em português.`;
|
||||
|
||||
const imagem = serie.placa
|
||||
? [{ url: serie.placa, width: 1600, height: 1091, alt: isEs ? `Patillaje de ${serie.nome_completo}` : isEn ? `Pinout of ${serie.nome_completo}` : `Pinagem do ${serie.nome_completo}` }]
|
||||
? [{ url: serie.placa, width: 1600, height: 1091, alt: isDe ? `Pinbelegung von ${serie.nome_completo}` : isFr ? `Brochage de ${serie.nome_completo}` : isEs ? `Patillaje de ${serie.nome_completo}` : isEn ? `Pinout of ${serie.nome_completo}` : `Pinagem do ${serie.nome_completo}` }]
|
||||
: [{ url: "/opengraph-image.png", width: 1200, height: 630, alt: "ESPDocs" }];
|
||||
|
||||
const keywords = isEs
|
||||
const keywords = isDe
|
||||
? [
|
||||
serie.nome_completo, `${serie.nome_completo} pinout`, `${serie.nome_completo} Pinbelegung`,
|
||||
`${serie.nome_completo} datasheet`, `${serie.nome_completo} Spezifikationen`,
|
||||
`${serie.nome_completo} deutsch`, "ESP32", "Espressif", "Mikrocontroller",
|
||||
]
|
||||
: isFr
|
||||
? [
|
||||
serie.nome_completo, `${serie.nome_completo} pinout`, `${serie.nome_completo} brochage`,
|
||||
`${serie.nome_completo} datasheet`, `${serie.nome_completo} spécifications`,
|
||||
`${serie.nome_completo} français`, "ESP32", "Espressif", "microcontrôleur",
|
||||
]
|
||||
: isEs
|
||||
? [
|
||||
serie.nome_completo, `${serie.nome_completo} pinout`, `${serie.nome_completo} patillaje`,
|
||||
`${serie.nome_completo} datasheet`, `${serie.nome_completo} especificaciones`,
|
||||
@@ -726,14 +972,32 @@ export async function generateMetadata({ params }) {
|
||||
|
||||
const meta = {
|
||||
...paginaMeta({
|
||||
titulo: isEs ? `${serie.nome_completo}: especificaciones y patillaje` : isEn ? `${serie.nome_completo}: specifications and pinout` : `${serie.nome_completo}: especificações e pinagem`,
|
||||
titulo: isDe
|
||||
? `${serie.nome_completo}: Spezifikationen und Pinbelegung`
|
||||
: isFr
|
||||
? `${serie.nome_completo} : spécifications et brochage`
|
||||
: isEs
|
||||
? `${serie.nome_completo}: especificaciones y patillaje`
|
||||
: isEn
|
||||
? `${serie.nome_completo}: specifications and pinout`
|
||||
: `${serie.nome_completo}: especificações e pinagem`,
|
||||
descricao,
|
||||
caminho: `/series/${key}`,
|
||||
tipo: "article",
|
||||
locale: currentLocale,
|
||||
keywords,
|
||||
}),
|
||||
other: { "article:section": isEs ? "Series ESP32" : isEn ? "ESP32 Series" : "Séries ESP32" },
|
||||
other: {
|
||||
"article:section": isDe
|
||||
? "ESP32-Serien"
|
||||
: isFr
|
||||
? "Séries ESP32"
|
||||
: isEs
|
||||
? "Series ESP32"
|
||||
: isEn
|
||||
? "ESP32 Series"
|
||||
: "Séries ESP32",
|
||||
},
|
||||
};
|
||||
|
||||
meta.openGraph = { ...meta.openGraph, images: imagem };
|
||||
|
||||
@@ -4,23 +4,41 @@ export async function generateMetadata({ params }) {
|
||||
const { locale } = await params;
|
||||
const isEn = locale === "en";
|
||||
const isEs = locale === "es";
|
||||
const isFr = locale === "fr";
|
||||
const isDe = locale === "de";
|
||||
const meta = paginaMeta({
|
||||
titulo: isEs ? "Series ESP32: Guía técnica y patillaje" : isEn ? "ESP32 Series: Technical Guide and Pinouts" : "Séries ESP32",
|
||||
descricao: isEs
|
||||
titulo: isDe
|
||||
? "ESP32-Serien: Technischer Leitfaden und Pinbelegung"
|
||||
: isFr
|
||||
? "Séries ESP32 : Guide technique et brochage"
|
||||
: isEs
|
||||
? "Series ESP32: Guía técnica y patillaje"
|
||||
: isEn
|
||||
? "ESP32 Series: Technical Guide and Pinouts"
|
||||
: "Séries ESP32",
|
||||
descricao: isDe
|
||||
? "Alle 12 ESP32-Serien Seite an Seite: ESP32, S2, S3, S31, C2, C3, C5, C6, C61, P4, H2 und H4. Architektur, Speicher, Funk, Peripherie und Pinbelegung jeder Serie."
|
||||
: isFr
|
||||
? "Les 12 séries d'ESP32 côte à côte : ESP32, S2, S3, S31, C2, C3, C5, C6, C61, P4, H2 et H4. Architecture, mémoire, radio, périphériques et brochage de chacune."
|
||||
: isEs
|
||||
? "Las 12 series de ESP32 lado a lado: ESP32, S2, S3, S31, C2, C3, C5, C6, C61, P4, H2 y H4. Arquitectura, memoria, radio, periféricos y patillaje de cada una."
|
||||
: isEn
|
||||
? "All 12 ESP32 series side by side: ESP32, S2, S3, S31, C2, C3, C5, C6, C61, P4, H2 and H4. Architecture, memory, radio, peripherals and pinouts for each one."
|
||||
: "As 12 séries de ESP32 lado a lado: ESP32, S2, S3, S31, C2, C3, C5, C6, C61, P4, H2 e H4. Arquitetura, memória, rádio, periféricos e pinagem de cada uma, em português.",
|
||||
caminho: "/series",
|
||||
locale,
|
||||
keywords: isEs
|
||||
keywords: isDe
|
||||
? ["ESP32-Serien", "ESP32-Modelle", "ESP32 S3", "ESP32 C6", "ESP32 P4", "Unterschied zwischen ESP32"]
|
||||
: isFr
|
||||
? ["séries ESP32", "modèles ESP32", "ESP32 S3", "ESP32 C6", "ESP32 P4", "différence entre ESP32"]
|
||||
: isEs
|
||||
? ["series ESP32", "modelos de ESP32", "ESP32 S3", "ESP32 C6", "ESP32 P4", "diferencia entre ESP32"]
|
||||
: isEn
|
||||
? ["ESP32 series", "ESP32 models", "ESP32 S3", "ESP32 C6", "ESP32 P4", "difference between ESP32"]
|
||||
: ["séries ESP32", "modelos de ESP32", "ESP32 S3", "ESP32 C6", "ESP32 P4", "diferença entre ESP32"],
|
||||
});
|
||||
meta.title = {
|
||||
default: isEs ? "Series ESP32" : isEn ? "ESP32 Series" : "Séries ESP32",
|
||||
default: isDe ? "ESP32-Serien" : isFr ? "Séries ESP32" : isEs ? "Series ESP32" : isEn ? "ESP32 Series" : "Séries ESP32",
|
||||
template: "%s · ESPDocs",
|
||||
};
|
||||
return meta;
|
||||
@@ -59,11 +77,35 @@ const faqsEs = [
|
||||
},
|
||||
];
|
||||
|
||||
const faqsFr = [
|
||||
{
|
||||
pergunta: "Combien de séries d'ESP32 existent actuellement ?",
|
||||
resposta: "Actuellement, l'écosystème Espressif compte 12 séries principales : ESP32 classique, ESP32-S2, ESP32-S3, ESP32-S31, ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-P4, ESP32-H2 et ESP32-H4.",
|
||||
},
|
||||
{
|
||||
pergunta: "Quelles sont les séries les plus récentes d'Espressif ?",
|
||||
resposta: "Les séries les plus récentes incluent l'ESP32-P4 (axé sur la haute performance avec dual-core RISC-V à 400 MHz), l'ESP32-C5 (première puce avec Wi-Fi bi-bande 2,4/5 GHz d'Espressif) et l'ESP32-C61 (Wi-Fi 6 et Bluetooth 6 à faible coût).",
|
||||
},
|
||||
];
|
||||
|
||||
const faqsDe = [
|
||||
{
|
||||
pergunta: "Wie viele ESP32-Serien gibt es derzeit?",
|
||||
resposta: "Derzeit umfasst das Espressif-Ökosystem 12 Hauptserien: klassischer ESP32, ESP32-S2, ESP32-S3, ESP32-S31, ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-P4, ESP32-H2 und ESP32-H4.",
|
||||
},
|
||||
{
|
||||
pergunta: "Welche sind die neuesten Serien von Espressif?",
|
||||
resposta: "Zu den neuesten Serien gehören der ESP32-P4 (fokussiert auf Hochleistung mit Dual-Core RISC-V bei 400 MHz), der ESP32-C5 (erster Chip mit Dual-Band 2,4/5 GHz Wi-Fi von Espressif) und der ESP32-C61 (kostengünstiges Wi-Fi 6 und Bluetooth 6).",
|
||||
},
|
||||
];
|
||||
|
||||
export default async function Layout({ children, params }) {
|
||||
const { locale } = await params;
|
||||
const isEn = locale === "en";
|
||||
const isEs = locale === "es";
|
||||
const faqs = isEs ? faqsEs : isEn ? faqsEn : faqsPt;
|
||||
const isFr = locale === "fr";
|
||||
const isDe = locale === "de";
|
||||
const faqs = isDe ? faqsDe : isFr ? faqsFr : isEs ? faqsEs : isEn ? faqsEn : faqsPt;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -72,8 +114,14 @@ export default async function Layout({ children, params }) {
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: JSON.stringify(
|
||||
jsonLd.trilha([
|
||||
{ nome: isEs ? "Inicio" : isEn ? "Home" : "Início", caminho: isEs ? "/es" : isEn ? "/en" : "/" },
|
||||
{ nome: isEs ? "Series ESP32" : isEn ? "ESP32 Series" : "Séries ESP32", caminho: isEs ? "/es/series" : isEn ? "/en/series" : "/series" },
|
||||
{
|
||||
nome: isDe ? "Startseite" : isFr ? "Accueil" : isEs ? "Inicio" : isEn ? "Home" : "Início",
|
||||
caminho: isDe ? "/de" : isFr ? "/fr" : isEs ? "/es" : isEn ? "/en" : "/",
|
||||
},
|
||||
{
|
||||
nome: isDe ? "ESP32-Serien" : isFr ? "Séries ESP32" : isEs ? "Series ESP32" : isEn ? "ESP32 Series" : "Séries ESP32",
|
||||
caminho: isDe ? "/de/serien" : isFr ? "/fr/series" : isEs ? "/es/series" : isEn ? "/en/series" : "/series",
|
||||
},
|
||||
])
|
||||
),
|
||||
}}
|
||||
|
||||
+106
-27
@@ -9,6 +9,8 @@ import Link from "next/link";
|
||||
import seriesDataPt from "@/public/series.json";
|
||||
import seriesDataEn from "@/data/en/series.json";
|
||||
import seriesDataEs from "@/data/es/series.json";
|
||||
import seriesDataFr from "@/data/fr/series.json";
|
||||
import seriesDataDe from "@/data/de/series.json";
|
||||
import { getLocalizedHref } from "@/i18n/links";
|
||||
import {
|
||||
AlertTriangle,
|
||||
@@ -45,31 +47,51 @@ const FILTROS_ES = [
|
||||
{ id: "ia", rotulo: "Aceleración de IA", testa: (s) => Boolean(s.aceleradores_ia) },
|
||||
];
|
||||
|
||||
const FILTROS_FR = [
|
||||
{ id: "todas", rotulo: "Toutes", testa: () => true },
|
||||
{ id: "riscv", rotulo: "RISC-V", testa: (s) => s.arquitetura.includes("RISC-V") },
|
||||
{ id: "xtensa", rotulo: "Xtensa", testa: (s) => !s.arquitetura.includes("RISC-V") },
|
||||
{ id: "matter", rotulo: "Matter", testa: (s) => s.matter === "Oui" || s.matter === "Yes" || s.matter === "Sim" || s.matter === "Sí" },
|
||||
{ id: "ia", rotulo: "Accélération IA", testa: (s) => Boolean(s.aceleradores_ia) },
|
||||
];
|
||||
|
||||
const FILTROS_DE = [
|
||||
{ id: "todas", rotulo: "Alle", testa: () => true },
|
||||
{ id: "riscv", rotulo: "RISC-V", testa: (s) => s.arquitetura.includes("RISC-V") },
|
||||
{ id: "xtensa", rotulo: "Xtensa", testa: (s) => !s.arquitetura.includes("RISC-V") },
|
||||
{ id: "matter", rotulo: "Matter", testa: (s) => s.matter === "Ja" || s.matter === "Yes" || s.matter === "Sim" || s.matter === "Sí" },
|
||||
{ id: "ia", rotulo: "KI-Beschleunigung", testa: (s) => Boolean(s.aceleradores_ia) },
|
||||
];
|
||||
|
||||
/** Marcador de segurança: o recurso que diferencia a série, não o que todas têm. */
|
||||
function nivelSeguranca(serie, isEn, isEs) {
|
||||
function nivelSeguranca(serie, isEn, isEs, isFr, isDe) {
|
||||
const seg = serie.seguranca || {};
|
||||
if (seg.key_manager === "Sim" || seg.key_manager === "Yes" || seg.key_manager === "Sí") return "Key Manager";
|
||||
if (String(seg.ecdsa).startsWith("Sim") || String(seg.ecdsa).startsWith("Yes") || String(seg.ecdsa).startsWith("Sí")) {
|
||||
return isEs ? "ECDSA en hardware" : isEn ? "Hardware ECDSA" : "ECDSA em hardware";
|
||||
if (seg.key_manager === "Sim" || seg.key_manager === "Yes" || seg.key_manager === "Sí" || seg.key_manager === "Oui" || seg.key_manager === "Ja") return "Key Manager";
|
||||
if (String(seg.ecdsa).startsWith("Sim") || String(seg.ecdsa).startsWith("Yes") || String(seg.ecdsa).startsWith("Sí") || String(seg.ecdsa).startsWith("Oui") || String(seg.ecdsa).startsWith("Ja")) {
|
||||
return isDe ? "Hardware-ECDSA" : isFr ? "ECDSA matériel" : isEs ? "ECDSA en hardware" : isEn ? "Hardware ECDSA" : "ECDSA em hardware";
|
||||
}
|
||||
if (String(seg.ecc).startsWith("Sim") || String(seg.ecc).startsWith("Yes") || String(seg.ecc).startsWith("Sí")) {
|
||||
return isEs ? "ECC en hardware" : isEn ? "Hardware ECC" : "ECC em hardware";
|
||||
if (String(seg.ecc).startsWith("Sim") || String(seg.ecc).startsWith("Yes") || String(seg.ecc).startsWith("Sí") || String(seg.ecc).startsWith("Oui") || String(seg.ecc).startsWith("Ja")) {
|
||||
return isDe ? "Hardware-ECC" : isFr ? "ECC matériel" : isEs ? "ECC en hardware" : isEn ? "Hardware ECC" : "ECC em hardware";
|
||||
}
|
||||
if (String(seg.aes).startsWith("AES")) return "AES + SHA";
|
||||
return isEs ? "Solo SHA" : isEn ? "SHA only" : "Só SHA";
|
||||
return isDe ? "Nur SHA" : isFr ? "SHA uniquement" : isEs ? "Solo SHA" : isEn ? "SHA only" : "Só SHA";
|
||||
}
|
||||
|
||||
const simPt = (v) => !String(v).includes("Não");
|
||||
const simEn = (v) => !String(v).includes("No") && !String(v).includes("Não");
|
||||
const simEs = (v) => !String(v).includes("No") && !String(v).includes("Não");
|
||||
const simFr = (v) => !String(v).includes("Non") && !String(v).includes("No") && !String(v).includes("Não");
|
||||
const simDe = (v) => !String(v).includes("Nein") && !String(v).includes("No") && !String(v).includes("Não");
|
||||
|
||||
export default function Series() {
|
||||
const pathname = usePathname();
|
||||
const isEn = pathname?.startsWith("/en");
|
||||
const isEs = pathname?.startsWith("/es");
|
||||
const currentLocale = isEs ? "es" : isEn ? "en" : "pt";
|
||||
const seriesData = isEs ? seriesDataEs : isEn ? seriesDataEn : seriesDataPt;
|
||||
const filtros = isEs ? FILTROS_ES : isEn ? FILTROS_EN : FILTROS_PT;
|
||||
const isFr = pathname?.startsWith("/fr");
|
||||
const isDe = pathname?.startsWith("/de");
|
||||
const currentLocale = isDe ? "de" : isFr ? "fr" : isEs ? "es" : isEn ? "en" : "pt";
|
||||
const seriesData = isDe ? seriesDataDe : isFr ? seriesDataFr : isEs ? seriesDataEs : isEn ? seriesDataEn : seriesDataPt;
|
||||
const filtros = isDe ? FILTROS_DE : isFr ? FILTROS_FR : isEs ? FILTROS_ES : isEn ? FILTROS_EN : FILTROS_PT;
|
||||
|
||||
const [filtro, setFiltro] = useState("todas");
|
||||
const todas = Object.entries(seriesData);
|
||||
@@ -84,12 +106,28 @@ export default function Series() {
|
||||
<PageHero
|
||||
isEn={isEn}
|
||||
isEs={isEs}
|
||||
trail={[{ label: isEs ? "Series" : isEn ? "Series" : "Séries" }]}
|
||||
isFr={isFr}
|
||||
isDe={isDe}
|
||||
trail={[{ label: isDe ? "Serien" : isFr ? "Séries" : isEs ? "Series" : isEn ? "Series" : "Séries" }]}
|
||||
icon={Compass}
|
||||
label={isEs ? `${todas.length} familias de Espressif` : isEn ? `${todas.length} Espressif families` : `${todas.length} famílias da Espressif`}
|
||||
title={isEs ? "Series ESP32" : isEn ? "ESP32 Series" : "Séries ESP32"}
|
||||
label={
|
||||
isDe
|
||||
? `${todas.length} Espressif-Familien`
|
||||
: isFr
|
||||
? `${todas.length} familles d'Espressif`
|
||||
: isEs
|
||||
? `${todas.length} familias de Espressif`
|
||||
: isEn
|
||||
? `${todas.length} Espressif families`
|
||||
: `${todas.length} famílias da Espressif`
|
||||
}
|
||||
title={isDe ? "ESP32-Serien" : isFr ? "Séries ESP32" : isEs ? "Series ESP32" : isEn ? "ESP32 Series" : "Séries ESP32"}
|
||||
lede={
|
||||
isEs
|
||||
isDe
|
||||
? "Jede Serie wurde für einen bestimmten Projekttyp entwickelt, von Batteriesensoren bis hin zu KI-Beschleunigern. Öffnen Sie das Datenblatt für Pinbelegung, Peripherie und Sicherheit."
|
||||
: isFr
|
||||
? "Chaque série a été conçue pour un type de projet spécifique, des capteurs sur batterie aux accélérateurs IA. Ouvrez la fiche pour consulter le brochage, les périphériques et la sécurité."
|
||||
: isEs
|
||||
? "Cada serie fue diseñada para un tipo de proyecto específico, desde sensores a batería hasta aceleradores de IA. Abra la ficha para ver patillaje, periféricos y seguridad."
|
||||
: isEn
|
||||
? "Each series was designed for a specific project type, from battery-powered sensors to AI accelerators. Open the sheet to see pinout, peripherals, and security."
|
||||
@@ -97,8 +135,8 @@ export default function Series() {
|
||||
}
|
||||
/>
|
||||
|
||||
<section className="shell pt-10 sm:pt-12" aria-label={isEs ? "Lista de series" : isEn ? "Series list" : "Lista de séries"}>
|
||||
<div role="group" aria-label={isEs ? "Filtrar series" : isEn ? "Filter series" : "Filtrar séries"} className="flex flex-wrap gap-2">
|
||||
<section className="shell pt-10 sm:pt-12" aria-label={isDe ? "Serienliste" : isFr ? "Liste des séries" : isEs ? "Lista de series" : isEn ? "Series list" : "Lista de séries"}>
|
||||
<div role="group" aria-label={isDe ? "Serien filtern" : isFr ? "Filtrer les séries" : isEs ? "Filtrar series" : isEn ? "Filter series" : "Filtrar séries"} className="flex flex-wrap gap-2">
|
||||
{filtros.map((f) => (
|
||||
<button key={f.id} type="button" aria-pressed={filtro === f.id} onClick={() => setFiltro(f.id)} className="chip-btn">
|
||||
{f.rotulo}
|
||||
@@ -106,13 +144,50 @@ export default function Series() {
|
||||
))}
|
||||
</div>
|
||||
<p role="status" aria-live="polite" className="mt-4 text-sm text-muted">
|
||||
{series.length} {series.length === 1 ? (isEs ? "serie" : isEn ? "series" : "série") : (isEs ? "series" : isEn ? "series" : "séries")}
|
||||
{series.length}{" "}
|
||||
{series.length === 1
|
||||
? isDe
|
||||
? "Serie"
|
||||
: isFr
|
||||
? "série"
|
||||
: isEs
|
||||
? "serie"
|
||||
: isEn
|
||||
? "series"
|
||||
: "série"
|
||||
: isDe
|
||||
? "Serien"
|
||||
: isFr
|
||||
? "séries"
|
||||
: isEs
|
||||
? "series"
|
||||
: isEn
|
||||
? "series"
|
||||
: "séries"}
|
||||
</p>
|
||||
|
||||
<div className="mt-4 grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
{series.map(([key, serie]) => {
|
||||
const riscv = serie.arquitetura.includes("RISC-V");
|
||||
const fatos = isEs
|
||||
const fatos = isDe
|
||||
? [
|
||||
["Kerne", serie.nucleos],
|
||||
["Taktfrequenz", serie.frequencia],
|
||||
["SRAM", serie.memoria_sram],
|
||||
["Wi-Fi", simDe(serie.wifi) ? "Ja" : "Nein"],
|
||||
["Bluetooth", String(serie.bluetooth).includes("Nein") || String(serie.bluetooth).includes("No") || String(serie.bluetooth).includes("Não") ? "Nein" : "Ja"],
|
||||
serie.consumo_energia?.deep_sleep ? ["Deep sleep", serie.consumo_energia.deep_sleep] : null,
|
||||
].filter(Boolean)
|
||||
: isFr
|
||||
? [
|
||||
["Cœurs", serie.nucleos],
|
||||
["Fréquence", serie.frequencia],
|
||||
["SRAM", serie.memoria_sram],
|
||||
["Wi-Fi", simFr(serie.wifi) ? "Oui" : "Non"],
|
||||
["Bluetooth", String(serie.bluetooth).includes("Non") || String(serie.bluetooth).includes("No") || String(serie.bluetooth).includes("Não") ? "Non" : "Oui"],
|
||||
serie.consumo_energia?.deep_sleep ? ["Deep sleep", serie.consumo_energia.deep_sleep] : null,
|
||||
].filter(Boolean)
|
||||
: isEs
|
||||
? [
|
||||
["Núcleos", serie.nucleos],
|
||||
["Frecuencia", serie.frequencia],
|
||||
@@ -150,7 +225,7 @@ export default function Series() {
|
||||
{fatos.map(([rotulo, valor]) => (
|
||||
<div key={rotulo} className="flex items-baseline justify-between gap-4 py-2">
|
||||
<dt className="text-muted">{rotulo}</dt>
|
||||
<dd className={`text-right font-medium ${valor === "Não" || valor === "No" ? "text-muted" : "text-ink"}`}>{valor}</dd>
|
||||
<dd className={`text-right font-medium ${valor === "Não" || valor === "No" || valor === "Non" || valor === "Nein" ? "text-muted" : "text-ink"}`}>{valor}</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
@@ -159,14 +234,14 @@ export default function Series() {
|
||||
{serie.aceleradores_ia && (
|
||||
<li className="chip chip-accent">
|
||||
<Sparkles className="h-3 w-3" aria-hidden="true" />
|
||||
{isEs ? "Aceleradores de IA" : isEn ? "AI Accelerators" : "Aceleradores de IA"}
|
||||
{isDe ? "KI-Beschleuniger" : isFr ? "Accélérateurs IA" : isEs ? "Aceleradores de IA" : isEn ? "AI Accelerators" : "Aceleradores de IA"}
|
||||
</li>
|
||||
)}
|
||||
<li className="chip">
|
||||
<ShieldCheck className="h-3 w-3 text-accent" aria-hidden="true" />
|
||||
{nivelSeguranca(serie, isEn, isEs)}
|
||||
{nivelSeguranca(serie, isEn, isEs, isFr, isDe)}
|
||||
</li>
|
||||
{(serie.matter === "Sim" || serie.matter === "Yes" || serie.matter === "Sí") && (
|
||||
{(serie.matter === "Sim" || serie.matter === "Yes" || serie.matter === "Sí" || serie.matter === "Oui" || serie.matter === "Ja") && (
|
||||
<li className="chip">
|
||||
<Home className="h-3 w-3 text-accent" aria-hidden="true" />
|
||||
Matter
|
||||
@@ -175,13 +250,13 @@ export default function Series() {
|
||||
{serie.status_documentacao && (
|
||||
<li className="chip">
|
||||
<AlertTriangle className="h-3 w-3 text-gold" aria-hidden="true" />
|
||||
{isEs ? "Documentación preliminar" : isEn ? "Preliminary documentation" : "Documentação preliminar"}
|
||||
{isDe ? "Vorläufige Dokumentation" : isFr ? "Documentation préliminaire" : isEs ? "Documentación preliminar" : isEn ? "Preliminary documentation" : "Documentação preliminar"}
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
|
||||
<span className="mt-5 inline-flex items-center gap-1 text-sm font-medium text-accent">
|
||||
{isEs ? "Abrir ficha" : isEn ? "Open datasheet" : "Abrir ficha"}
|
||||
{isDe ? "Datenblatt öffnen" : isFr ? "Ouvrir la fiche" : isEs ? "Abrir ficha" : isEn ? "Open datasheet" : "Abrir ficha"}
|
||||
<ArrowUpRight className="h-4 w-4 transition-transform group-hover:-translate-y-0.5 group-hover:translate-x-0.5" aria-hidden="true" />
|
||||
</span>
|
||||
</Link>
|
||||
@@ -194,10 +269,14 @@ export default function Series() {
|
||||
<div className="panel flex flex-col items-start justify-between gap-6 p-7 sm:p-10 md:flex-row md:items-center">
|
||||
<div className="max-w-2xl">
|
||||
<h2 className="section-title">
|
||||
{isEs ? "¿Tiene dudas entre dos series?" : isEn ? "Unsure between two series?" : "Ficou em dúvida entre duas séries?"}
|
||||
{isDe ? "Unsicher zwischen zwei Serien?" : isFr ? "Vous hésitez entre deux séries ?" : isEs ? "¿Tiene dudas entre dos series?" : isEn ? "Unsure between two series?" : "Ficou em dúvida entre duas séries?"}
|
||||
</h2>
|
||||
<p className="mt-3 text-base text-muted">
|
||||
{isEs
|
||||
{isDe
|
||||
? "Der Vergleicher stellt bis zu vier Modelle gegenüber: Kerne, Funk, Speicher, Peripherie und Sicherheit."
|
||||
: isFr
|
||||
? "Le comparateur place jusqu'à quatre modèles côte à côte : cœurs, radio, mémoire, périphériques et sécurité."
|
||||
: isEs
|
||||
? "El comparador coloca hasta cuatro modelos lado a lado: núcleos, radio, memoria, periféricos y seguridad."
|
||||
: isEn
|
||||
? "The comparator tool puts up to four models side by side: cores, radio, memory, peripherals, and security."
|
||||
@@ -206,7 +285,7 @@ export default function Series() {
|
||||
</div>
|
||||
<Link href={getLocalizedHref("/comparacao", currentLocale)} className="btn btn-primary shrink-0">
|
||||
<Scale className="h-4 w-4" aria-hidden="true" />
|
||||
{isEs ? "Comparar series" : isEn ? "Compare series" : "Comparar séries"}
|
||||
{isDe ? "Serien vergleichen" : isFr ? "Comparer les séries" : isEs ? "Comparar series" : isEn ? "Compare series" : "Comparar séries"}
|
||||
<ArrowRight className="h-4 w-4" aria-hidden="true" />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user