From ecc35f72cbb928378fa9eac0835ef99dd3804234 Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Sat, 9 May 2026 03:20:36 -0300 Subject: [PATCH] feat(editor): translate SimulatorCanvas header + remove dialog (Editor block 4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The canvas header (the bar above the simulation area) and the "Remove board?" confirmation dialog now read from i18n. Translated: - Status dot tooltip (Running / Stopped). - Active board selector tooltip + "No board" placeholder + the hint that prompts the user to add a board. - Undo / Redo buttons: aria-label, dynamic title with the action description and the empty-state fallback. Action descriptions themselves stay untranslated (they come from the editor history store as English literals — translating them would mean reaching into a different store; deferred). - Serial Monitor and Oscilloscope toggles (button title + label). - Zoom in / out / reset-view buttons. - Component count tooltip + Add Component button. - The error-banner Dismiss button. - "Remove board" item in the right-click menu, with a localised "(N wires)" parenthetical via i18next pluralisation. - The full removal confirmation dialog: title with board label interpolation, body copy with optional connected-wires sentence, Cancel + Remove buttons. Pluralisation uses i18next's _one / _other (and _few / _many for Russian) suffixes so wire counts read naturally per language. Hand-translated for all 8 non-English locales. Untouched (deferred): the property dialog, custom-chip dialog, sensor control panel, and the various inline tooltips on board pins and wire endpoints — those are denser and benefit from a separate pass. --- .../components/simulator/SimulatorCanvas.tsx | 70 +++++++++---------- frontend/src/i18n/locales/de/common.json | 43 ++++++++++++ frontend/src/i18n/locales/en/common.json | 43 ++++++++++++ frontend/src/i18n/locales/es/common.json | 43 ++++++++++++ frontend/src/i18n/locales/fr/common.json | 43 ++++++++++++ frontend/src/i18n/locales/it/common.json | 43 ++++++++++++ frontend/src/i18n/locales/ja/common.json | 40 +++++++++++ frontend/src/i18n/locales/pt-br/common.json | 43 ++++++++++++ frontend/src/i18n/locales/ru/common.json | 49 +++++++++++++ frontend/src/i18n/locales/zh-cn/common.json | 40 +++++++++++ 10 files changed, 419 insertions(+), 38 deletions(-) diff --git a/frontend/src/components/simulator/SimulatorCanvas.tsx b/frontend/src/components/simulator/SimulatorCanvas.tsx index 42837e61..b6183562 100644 --- a/frontend/src/components/simulator/SimulatorCanvas.tsx +++ b/frontend/src/components/simulator/SimulatorCanvas.tsx @@ -2,6 +2,7 @@ import { useSimulatorStore, getEsp32Bridge } from '../../store/useSimulatorStore import React, { useEffect, useState, useRef, useCallback } from 'react'; import { createPortal } from 'react-dom'; import { Undo2, Redo2 } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; import { ESP32_ADC_PIN_MAP } from '../velxio-components/Esp32Element'; import { ComponentPickerModal } from '../ComponentPickerModal'; import { ComponentPropertyDialog } from './ComponentPropertyDialog'; @@ -87,6 +88,7 @@ interface SimulatorCanvasProps { } export const SimulatorCanvas = ({ headerSlot }: SimulatorCanvasProps = {}) => { + const { t } = useTranslation(); const isTouchDevice = useIsCoarsePointer(); // Mirror to a ref so the long-lived touch handler effect (deps deliberately // narrow to avoid rebinding listeners on every render) can read the latest @@ -1866,7 +1868,7 @@ export const SimulatorCanvas = ({ headerSlot }: SimulatorCanvasProps = {}) => { cursor: 'pointer', }} > - Dismiss + {t('editor.canvas.dismiss')} )} @@ -1880,7 +1882,7 @@ export const SimulatorCanvas = ({ headerSlot }: SimulatorCanvasProps = {}) => { {/* Status LED */} {/* Active board selector (multi-board) — hidden when no boards */} @@ -1890,7 +1892,7 @@ export const SimulatorCanvas = ({ headerSlot }: SimulatorCanvasProps = {}) => { value={activeBoardId ?? ''} onChange={(e) => useSimulatorStore.getState().setActiveBoardId(e.target.value)} disabled={running} - title="Active board" + title={t('editor.canvas.activeBoard')} > {boards.map((b) => (