From ea290d0c22e4e36de4a6eace21351b674b13da8f Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Sat, 9 May 2026 11:35:22 -0300 Subject: [PATCH] feat(editor): translate InstallLibrariesModal + SerialMonitor (Editor block 8) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit InstallLibrariesModal — auto-install prompt that fires when an example needs libraries: - Title, subtitle (with the "Installing X of Y" progress interpolation, the all-done success state, and the singular / plural prompt explaining the requirement count). - Per-row status badges (pending / installing… / installed / error) plus the Wokwi-hosted-library tooltip. - Footer buttons: Close / Skip / "Install All ({{count}})" with loading variant. SerialMonitor — multi-board tabbed serial console: - Empty-state when no board is on the canvas. - Right-side tab controls: Autoscroll checkbox, Clear button + tooltip. - The "(Open IoT Gateway)" inline link rendered next to detected AP IP addresses. - Output-area placeholders for the running-but-no-data and before-start states. - Send button + input placeholder (different copy for MicroPython REPL vs raw Serial input). - The line-ending dropdown options (None / Newline / Carriage return / Both). Hand-translated for all 9 locales. Hotkeys (Ctrl+C) and dropdown values stay untranslated (constants the firmware reads). Pending in Phase 3: - Oscilloscope panel, custom-chip dialog, sensor control panel. - ComponentPropertyDialog (per-component property forms). - Admin / Profile / Project pages. - Long-form docs prose (DocsPage 2715 lines, AboutPage long paragraphs). - 15 SEO landing pages (intentionally English for keyword targeting). --- .../simulator/InstallLibrariesModal.tsx | 34 +++++++++-------- .../components/simulator/SerialMonitor.tsx | 34 +++++++++-------- frontend/src/i18n/locales/de/common.json | 36 ++++++++++++++++++ frontend/src/i18n/locales/en/common.json | 36 ++++++++++++++++++ frontend/src/i18n/locales/es/common.json | 36 ++++++++++++++++++ frontend/src/i18n/locales/fr/common.json | 36 ++++++++++++++++++ frontend/src/i18n/locales/it/common.json | 36 ++++++++++++++++++ frontend/src/i18n/locales/ja/common.json | 35 +++++++++++++++++ frontend/src/i18n/locales/pt-br/common.json | 36 ++++++++++++++++++ frontend/src/i18n/locales/ru/common.json | 38 +++++++++++++++++++ frontend/src/i18n/locales/zh-cn/common.json | 35 +++++++++++++++++ 11 files changed, 360 insertions(+), 32 deletions(-) diff --git a/frontend/src/components/simulator/InstallLibrariesModal.tsx b/frontend/src/components/simulator/InstallLibrariesModal.tsx index c062bc7e..669aed3f 100644 --- a/frontend/src/components/simulator/InstallLibrariesModal.tsx +++ b/frontend/src/components/simulator/InstallLibrariesModal.tsx @@ -1,4 +1,5 @@ import React, { useState, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; import { installLibrary } from '../../services/libraryService'; import './InstallLibrariesModal.css'; @@ -58,6 +59,7 @@ export const InstallLibrariesModal: React.FC = ({ onClose, libraries, }) => { + const { t } = useTranslation(); const [items, setItems] = useState(() => libraries.map((spec) => { const { name, version } = parseLibSpec(spec); @@ -134,7 +136,7 @@ export const InstallLibrariesModal: React.FC = ({ - REQUIRED LIBRARIES + {t('editor.installLibs.title')} ) : ( <> diff --git a/frontend/src/components/simulator/SerialMonitor.tsx b/frontend/src/components/simulator/SerialMonitor.tsx index 7158854d..c5386679 100644 --- a/frontend/src/components/simulator/SerialMonitor.tsx +++ b/frontend/src/components/simulator/SerialMonitor.tsx @@ -4,6 +4,7 @@ */ import React, { useRef, useEffect, useState, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; import { useSimulatorStore } from '../../store/useSimulatorStore'; import { getTabSessionId } from '../../simulation/Esp32Bridge'; import type { BoardKind } from '../../types/board'; @@ -71,6 +72,7 @@ const BOARD_COLOR: Partial> = { }; export const SerialMonitor: React.FC = () => { + const { t } = useTranslation(); const boards = useSimulatorStore((s) => s.boards); const activeBoardId = useSimulatorStore((s) => s.activeBoardId); const serialWriteToBoard = useSimulatorStore((s) => s.serialWriteToBoard); @@ -176,9 +178,9 @@ export const SerialMonitor: React.FC = () => { return (
- Serial Monitor + {t('editor.serial.title')}
-
Add a board to start the serial monitor.
+
{t('editor.serial.addBoard')}
); } @@ -231,14 +233,14 @@ export const SerialMonitor: React.FC = () => { onChange={(e) => setAutoscroll(e.target.checked)} style={styles.checkbox} /> - Autoscroll + {t('editor.serial.autoscroll')} @@ -284,9 +286,9 @@ export const SerialMonitor: React.FC = () => { fontWeight: 'bold', cursor: 'pointer', }} - title="Click to open through IoT Gateway" + title={t('editor.serial.iotGatewayTitle')} > - {m[0]} (Open IoT Gateway ↗) + {m[0]} ({t('editor.serial.openIotGateway')} ↗) , ); lastIdx = end; @@ -297,8 +299,8 @@ export const SerialMonitor: React.FC = () => { return text; })() : activeBoard?.running - ? 'Waiting for serial data...\n' - : 'Start simulation to see serial output.\n'} + ? t('editor.serial.waitingData') + '\n' + : t('editor.serial.startSim') + '\n'} {/* Input row */} @@ -310,8 +312,8 @@ export const SerialMonitor: React.FC = () => { onKeyDown={handleKeyDown} placeholder={ isMicroPython - ? 'Type Python expression... (Ctrl+C to interrupt)' - : 'Type message to send...' + ? t('editor.serial.placeholderPython') + : t('editor.serial.placeholderText') } style={styles.input} disabled={!activeBoard?.running} @@ -321,13 +323,13 @@ export const SerialMonitor: React.FC = () => { onChange={(e) => setLineEnding(e.target.value as typeof lineEnding)} style={styles.select} > - - - - + + + + diff --git a/frontend/src/i18n/locales/de/common.json b/frontend/src/i18n/locales/de/common.json index 5cb8d6eb..143c263d 100644 --- a/frontend/src/i18n/locales/de/common.json +++ b/frontend/src/i18n/locales/de/common.json @@ -333,6 +333,42 @@ "loadingInstalled": "Installierte Bibliotheken werden geladen...", "noneInstalled": "Noch keine Bibliotheken installiert.", "useSearchTab": "Nutze den Tab Suchen, um Bibliotheken zu installieren." + }, + "installLibs": { + "title": "ERFORDERLICHE BIBLIOTHEKEN", + "installingProgress": "Installiere {{done}} von {{total}}…", + "allDone": "Alle Bibliotheken erfolgreich installiert", + "required_one": "Dieses Projekt benötigt {{count}} Bibliothek. Installiere sie, um korrekt zu kompilieren.", + "required_other": "Dieses Projekt benötigt {{count}} Bibliotheken. Installiere sie, um korrekt zu kompilieren.", + "wokwiHosted": "Von Wokwi gehostete Bibliothek", + "pending": "ausstehend", + "installing": "installiere…", + "installed": "installiert", + "errorStatus": "Fehler", + "close": "Schließen", + "skip": "Überspringen", + "installAll": "Alle installieren ({{count}})", + "installingShort": "Installiere…" + }, + "serial": { + "title": "Serial Monitor", + "addBoard": "Füge ein Board hinzu, um den Serial Monitor zu starten.", + "autoscroll": "Auto-Scroll", + "clearTitle": "Ausgabe dieses Boards löschen", + "clear": "Löschen", + "send": "Senden", + "iotGatewayTitle": "Klicken, um über IoT Gateway zu öffnen", + "openIotGateway": "IoT Gateway öffnen", + "waitingData": "Warte auf serielle Daten...", + "startSim": "Starte die Simulation, um serielle Ausgabe zu sehen.", + "placeholderText": "Nachricht zum Senden eingeben...", + "placeholderPython": "Python-Ausdruck eingeben... (Strg+C zum Abbrechen)", + "lineEnd": { + "none": "Kein Zeilenende", + "nl": "Zeilenumbruch", + "cr": "Wagenrücklauf", + "both": "NL und CR" + } } } } diff --git a/frontend/src/i18n/locales/en/common.json b/frontend/src/i18n/locales/en/common.json index 9e749974..193cd27b 100644 --- a/frontend/src/i18n/locales/en/common.json +++ b/frontend/src/i18n/locales/en/common.json @@ -333,6 +333,42 @@ "loadingInstalled": "Loading installed libraries...", "noneInstalled": "No libraries installed yet.", "useSearchTab": "Use the Search tab to install libraries." + }, + "installLibs": { + "title": "REQUIRED LIBRARIES", + "installingProgress": "Installing {{done}} of {{total}}…", + "allDone": "All libraries installed successfully", + "required_one": "This project requires {{count}} library. Install it to compile correctly.", + "required_other": "This project requires {{count}} libraries. Install them to compile correctly.", + "wokwiHosted": "Wokwi-hosted library", + "pending": "pending", + "installing": "installing…", + "installed": "installed", + "errorStatus": "error", + "close": "Close", + "skip": "Skip", + "installAll": "Install All ({{count}})", + "installingShort": "Installing…" + }, + "serial": { + "title": "Serial Monitor", + "addBoard": "Add a board to start the serial monitor.", + "autoscroll": "Autoscroll", + "clearTitle": "Clear output for this board", + "clear": "Clear", + "send": "Send", + "iotGatewayTitle": "Click to open through IoT Gateway", + "openIotGateway": "Open IoT Gateway", + "waitingData": "Waiting for serial data...", + "startSim": "Start simulation to see serial output.", + "placeholderText": "Type message to send...", + "placeholderPython": "Type Python expression... (Ctrl+C to interrupt)", + "lineEnd": { + "none": "No line ending", + "nl": "Newline", + "cr": "Carriage return", + "both": "Both NL & CR" + } } } } diff --git a/frontend/src/i18n/locales/es/common.json b/frontend/src/i18n/locales/es/common.json index 7c6bfc7a..80b15e27 100644 --- a/frontend/src/i18n/locales/es/common.json +++ b/frontend/src/i18n/locales/es/common.json @@ -333,6 +333,42 @@ "loadingInstalled": "Cargando librerías instaladas...", "noneInstalled": "Aún no hay librerías instaladas.", "useSearchTab": "Usa la pestaña Buscar para instalar librerías." + }, + "installLibs": { + "title": "LIBRERÍAS REQUERIDAS", + "installingProgress": "Instalando {{done}} de {{total}}…", + "allDone": "Todas las librerías se instalaron correctamente", + "required_one": "Este proyecto requiere {{count}} librería. Instálala para compilar correctamente.", + "required_other": "Este proyecto requiere {{count}} librerías. Instálalas para compilar correctamente.", + "wokwiHosted": "Librería alojada en Wokwi", + "pending": "pendiente", + "installing": "instalando…", + "installed": "instalada", + "errorStatus": "error", + "close": "Cerrar", + "skip": "Omitir", + "installAll": "Instalar todas ({{count}})", + "installingShort": "Instalando…" + }, + "serial": { + "title": "Monitor serie", + "addBoard": "Añade una placa para iniciar el monitor serie.", + "autoscroll": "Autoscroll", + "clearTitle": "Limpiar la salida de esta placa", + "clear": "Limpiar", + "send": "Enviar", + "iotGatewayTitle": "Haz clic para abrir a través de IoT Gateway", + "openIotGateway": "Abrir IoT Gateway", + "waitingData": "Esperando datos serie...", + "startSim": "Inicia la simulación para ver la salida serie.", + "placeholderText": "Escribe un mensaje para enviar...", + "placeholderPython": "Escribe expresión Python... (Ctrl+C para interrumpir)", + "lineEnd": { + "none": "Sin terminador de línea", + "nl": "Nueva línea", + "cr": "Retorno de carro", + "both": "Ambos NL y CR" + } } } } diff --git a/frontend/src/i18n/locales/fr/common.json b/frontend/src/i18n/locales/fr/common.json index b8ef66c6..7a0898fa 100644 --- a/frontend/src/i18n/locales/fr/common.json +++ b/frontend/src/i18n/locales/fr/common.json @@ -333,6 +333,42 @@ "loadingInstalled": "Chargement des bibliothèques installées...", "noneInstalled": "Aucune bibliothèque installée pour le moment.", "useSearchTab": "Utilisez l'onglet Rechercher pour installer des bibliothèques." + }, + "installLibs": { + "title": "BIBLIOTHÈQUES REQUISES", + "installingProgress": "Installation {{done}} sur {{total}}…", + "allDone": "Toutes les bibliothèques ont été installées avec succès", + "required_one": "Ce projet nécessite {{count}} bibliothèque. Installez-la pour compiler correctement.", + "required_other": "Ce projet nécessite {{count}} bibliothèques. Installez-les pour compiler correctement.", + "wokwiHosted": "Bibliothèque hébergée par Wokwi", + "pending": "en attente", + "installing": "installation…", + "installed": "installée", + "errorStatus": "erreur", + "close": "Fermer", + "skip": "Ignorer", + "installAll": "Tout installer ({{count}})", + "installingShort": "Installation…" + }, + "serial": { + "title": "Moniteur série", + "addBoard": "Ajoutez une carte pour démarrer le moniteur série.", + "autoscroll": "Défilement auto", + "clearTitle": "Effacer la sortie de cette carte", + "clear": "Effacer", + "send": "Envoyer", + "iotGatewayTitle": "Cliquez pour ouvrir via IoT Gateway", + "openIotGateway": "Ouvrir IoT Gateway", + "waitingData": "En attente de données série...", + "startSim": "Démarrez la simulation pour voir la sortie série.", + "placeholderText": "Tapez un message à envoyer...", + "placeholderPython": "Tapez une expression Python... (Ctrl+C pour interrompre)", + "lineEnd": { + "none": "Aucune fin de ligne", + "nl": "Nouvelle ligne", + "cr": "Retour chariot", + "both": "NL et CR" + } } } } diff --git a/frontend/src/i18n/locales/it/common.json b/frontend/src/i18n/locales/it/common.json index 2c2f6083..39ae4955 100644 --- a/frontend/src/i18n/locales/it/common.json +++ b/frontend/src/i18n/locales/it/common.json @@ -333,6 +333,42 @@ "loadingInstalled": "Caricamento librerie installate...", "noneInstalled": "Nessuna libreria ancora installata.", "useSearchTab": "Usa la scheda Cerca per installare librerie." + }, + "installLibs": { + "title": "LIBRERIE RICHIESTE", + "installingProgress": "Installazione {{done}} di {{total}}…", + "allDone": "Tutte le librerie sono state installate correttamente", + "required_one": "Questo progetto richiede {{count}} libreria. Installala per compilare correttamente.", + "required_other": "Questo progetto richiede {{count}} librerie. Installale per compilare correttamente.", + "wokwiHosted": "Libreria ospitata da Wokwi", + "pending": "in attesa", + "installing": "installazione…", + "installed": "installata", + "errorStatus": "errore", + "close": "Chiudi", + "skip": "Salta", + "installAll": "Installa tutte ({{count}})", + "installingShort": "Installazione…" + }, + "serial": { + "title": "Monitor seriale", + "addBoard": "Aggiungi una scheda per avviare il monitor seriale.", + "autoscroll": "Autoscroll", + "clearTitle": "Cancella l'output di questa scheda", + "clear": "Cancella", + "send": "Invia", + "iotGatewayTitle": "Clic per aprire tramite IoT Gateway", + "openIotGateway": "Apri IoT Gateway", + "waitingData": "In attesa di dati seriali...", + "startSim": "Avvia la simulazione per vedere l'output seriale.", + "placeholderText": "Scrivi un messaggio da inviare...", + "placeholderPython": "Scrivi espressione Python... (Ctrl+C per interrompere)", + "lineEnd": { + "none": "Nessun fine riga", + "nl": "Newline", + "cr": "Ritorno carrello", + "both": "Entrambi NL e CR" + } } } } diff --git a/frontend/src/i18n/locales/ja/common.json b/frontend/src/i18n/locales/ja/common.json index 99768388..c9fc8989 100644 --- a/frontend/src/i18n/locales/ja/common.json +++ b/frontend/src/i18n/locales/ja/common.json @@ -329,6 +329,41 @@ "loadingInstalled": "インストール済みライブラリを読み込み中...", "noneInstalled": "まだライブラリはインストールされていません。", "useSearchTab": "ライブラリをインストールするには「検索」タブを使用してください。" + }, + "installLibs": { + "title": "必要なライブラリ", + "installingProgress": "インストール中 {{done}}/{{total}}…", + "allDone": "すべてのライブラリが正常にインストールされました", + "required_other": "このプロジェクトには {{count}} 個のライブラリが必要です。正しくコンパイルするためにインストールしてください。", + "wokwiHosted": "Wokwi 提供ライブラリ", + "pending": "待機中", + "installing": "インストール中…", + "installed": "インストール済み", + "errorStatus": "エラー", + "close": "閉じる", + "skip": "スキップ", + "installAll": "すべてインストール({{count}})", + "installingShort": "インストール中…" + }, + "serial": { + "title": "シリアルモニタ", + "addBoard": "シリアルモニタを開始するにはボードを追加してください。", + "autoscroll": "自動スクロール", + "clearTitle": "このボードの出力をクリア", + "clear": "クリア", + "send": "送信", + "iotGatewayTitle": "クリックで IoT Gateway 経由で開く", + "openIotGateway": "IoT Gateway を開く", + "waitingData": "シリアルデータを待機中...", + "startSim": "シミュレーションを開始するとシリアル出力が表示されます。", + "placeholderText": "送信するメッセージを入力...", + "placeholderPython": "Python 式を入力...(Ctrl+C で中断)", + "lineEnd": { + "none": "改行なし", + "nl": "LF(改行)", + "cr": "CR(復帰)", + "both": "NL と CR" + } } } } diff --git a/frontend/src/i18n/locales/pt-br/common.json b/frontend/src/i18n/locales/pt-br/common.json index 684285b6..a44552f5 100644 --- a/frontend/src/i18n/locales/pt-br/common.json +++ b/frontend/src/i18n/locales/pt-br/common.json @@ -333,6 +333,42 @@ "loadingInstalled": "Carregando bibliotecas instaladas...", "noneInstalled": "Nenhuma biblioteca instalada ainda.", "useSearchTab": "Use a aba Buscar para instalar bibliotecas." + }, + "installLibs": { + "title": "BIBLIOTECAS NECESSÁRIAS", + "installingProgress": "Instalando {{done}} de {{total}}…", + "allDone": "Todas as bibliotecas foram instaladas com sucesso", + "required_one": "Este projeto requer {{count}} biblioteca. Instale para compilar corretamente.", + "required_other": "Este projeto requer {{count}} bibliotecas. Instale-as para compilar corretamente.", + "wokwiHosted": "Biblioteca hospedada na Wokwi", + "pending": "pendente", + "installing": "instalando…", + "installed": "instalada", + "errorStatus": "erro", + "close": "Fechar", + "skip": "Pular", + "installAll": "Instalar todas ({{count}})", + "installingShort": "Instalando…" + }, + "serial": { + "title": "Monitor serial", + "addBoard": "Adicione uma placa para iniciar o monitor serial.", + "autoscroll": "Autoscroll", + "clearTitle": "Limpar a saída desta placa", + "clear": "Limpar", + "send": "Enviar", + "iotGatewayTitle": "Clique para abrir via IoT Gateway", + "openIotGateway": "Abrir IoT Gateway", + "waitingData": "Aguardando dados serial...", + "startSim": "Inicie a simulação para ver a saída serial.", + "placeholderText": "Digite uma mensagem para enviar...", + "placeholderPython": "Digite expressão Python... (Ctrl+C para interromper)", + "lineEnd": { + "none": "Sem terminador de linha", + "nl": "Nova linha", + "cr": "Retorno de carro", + "both": "Ambos NL e CR" + } } } } diff --git a/frontend/src/i18n/locales/ru/common.json b/frontend/src/i18n/locales/ru/common.json index ead46b94..2072a834 100644 --- a/frontend/src/i18n/locales/ru/common.json +++ b/frontend/src/i18n/locales/ru/common.json @@ -341,6 +341,44 @@ "loadingInstalled": "Загрузка установленных библиотек...", "noneInstalled": "Пока нет установленных библиотек.", "useSearchTab": "Используйте вкладку Поиск, чтобы установить библиотеки." + }, + "installLibs": { + "title": "ТРЕБУЕМЫЕ БИБЛИОТЕКИ", + "installingProgress": "Установка {{done}} из {{total}}…", + "allDone": "Все библиотеки успешно установлены", + "required_one": "Этому проекту нужна {{count}} библиотека. Установите её, чтобы корректно скомпилировать.", + "required_few": "Этому проекту нужны {{count}} библиотеки. Установите их, чтобы корректно скомпилировать.", + "required_many": "Этому проекту нужны {{count}} библиотек. Установите их, чтобы корректно скомпилировать.", + "required_other": "Этому проекту нужны {{count}} библиотек. Установите их, чтобы корректно скомпилировать.", + "wokwiHosted": "Библиотека на серверах Wokwi", + "pending": "в очереди", + "installing": "устанавливается…", + "installed": "установлена", + "errorStatus": "ошибка", + "close": "Закрыть", + "skip": "Пропустить", + "installAll": "Установить всё ({{count}})", + "installingShort": "Установка…" + }, + "serial": { + "title": "Serial Monitor", + "addBoard": "Добавьте плату, чтобы запустить Serial Monitor.", + "autoscroll": "Автопрокрутка", + "clearTitle": "Очистить вывод для этой платы", + "clear": "Очистить", + "send": "Отправить", + "iotGatewayTitle": "Нажмите, чтобы открыть через IoT Gateway", + "openIotGateway": "Открыть IoT Gateway", + "waitingData": "Ожидание serial-данных...", + "startSim": "Запустите симуляцию, чтобы увидеть serial-вывод.", + "placeholderText": "Введите сообщение для отправки...", + "placeholderPython": "Введите Python-выражение... (Ctrl+C — прерывание)", + "lineEnd": { + "none": "Без перевода строки", + "nl": "Newline", + "cr": "Carriage return", + "both": "NL и CR" + } } } } diff --git a/frontend/src/i18n/locales/zh-cn/common.json b/frontend/src/i18n/locales/zh-cn/common.json index 23a42c38..390d3580 100644 --- a/frontend/src/i18n/locales/zh-cn/common.json +++ b/frontend/src/i18n/locales/zh-cn/common.json @@ -329,6 +329,41 @@ "loadingInstalled": "正在加载已安装的库...", "noneInstalled": "尚未安装任何库。", "useSearchTab": "请在「搜索」标签中安装库。" + }, + "installLibs": { + "title": "所需的库", + "installingProgress": "正在安装 {{done}}/{{total}}…", + "allDone": "所有库已成功安装", + "required_other": "本项目需要 {{count}} 个库。请安装以便正确编译。", + "wokwiHosted": "由 Wokwi 托管的库", + "pending": "待安装", + "installing": "正在安装…", + "installed": "已安装", + "errorStatus": "错误", + "close": "关闭", + "skip": "跳过", + "installAll": "全部安装({{count}})", + "installingShort": "正在安装…" + }, + "serial": { + "title": "串口监视器", + "addBoard": "请先添加开发板以启动串口监视器。", + "autoscroll": "自动滚动", + "clearTitle": "清空此开发板的输出", + "clear": "清空", + "send": "发送", + "iotGatewayTitle": "点击通过 IoT Gateway 打开", + "openIotGateway": "打开 IoT Gateway", + "waitingData": "等待串口数据...", + "startSim": "启动仿真以查看串口输出。", + "placeholderText": "输入要发送的消息...", + "placeholderPython": "输入 Python 表达式...(按 Ctrl+C 中断)", + "lineEnd": { + "none": "无行结束符", + "nl": "换行符", + "cr": "回车符", + "both": "换行 + 回车" + } } } }