From 55df49f6ab660c86f0b7125cec70dc4e533c8780 Mon Sep 17 00:00:00 2001 From: Sadallah Date: Wed, 10 Jun 2026 23:51:08 +0200 Subject: [PATCH] [Chore] Translate French comments and UI strings to English --- webapp/backend/routes/submit.py | 4 +- webapp/backend/services/helmService.py | 7 ++- webapp/backend/services/utils.py | 45 ++++++++++--------- webapp/backend/utils/validators.py | 4 +- webapp/frontend/src/App.jsx | 2 +- .../src/components/common/HistoryPanel.jsx | 4 +- .../components/common/PanZoomContainer.jsx | 20 ++++----- .../src/components/common/ProgressBar.jsx | 6 +-- .../frontend/src/components/common/Tabs.jsx | 4 +- .../src/components/tabs/HelmFileTab/index.jsx | 2 +- .../src/components/tabs/HelmTab/index.jsx | 4 +- .../src/components/tabs/ManifestTab/index.jsx | 2 +- webapp/frontend/src/utils/toast.js | 6 +-- 13 files changed, 56 insertions(+), 54 deletions(-) diff --git a/webapp/backend/routes/submit.py b/webapp/backend/routes/submit.py index c8144b4..01b8efb 100644 --- a/webapp/backend/routes/submit.py +++ b/webapp/backend/routes/submit.py @@ -23,13 +23,13 @@ def submit_feedback(): if note or comment: try: with open(Config.FEEDBACK_FILE, "a", encoding="utf-8") as f: - f.write(f"[{diagram_type.upper()}]\nNote: {note}\nCommentaire: {comment}\n\n") + f.write(f"[{diagram_type.upper()}]\nNote: {note}\nComment: {comment}\n\n") return ResponseBuilder.success( message="Feedback submitted successfully. Thank you!" ) except Exception as e: - # Log l'erreur dans le CSV + # Log error to CSV csv_logger = logging.getLogger(Config.LOGGER_NAME) csv_logger.error(f"Error writing feedback: {e}") return ResponseBuilder.error( diff --git a/webapp/backend/services/helmService.py b/webapp/backend/services/helmService.py index 26c65a7..ca1f2e7 100644 --- a/webapp/backend/services/helmService.py +++ b/webapp/backend/services/helmService.py @@ -25,11 +25,11 @@ def generate_from_helm( Returns: DiagramResult: Result of the generation """ - # Extraction du nom de base + # Extract base name for output file parsed = urlparse(chart_url) base_name = os.path.basename(parsed.path).replace(".tgz", "").replace(".tar.gz", "") - # Pour les URLs OCI + # OCI URLs use the last path segment as chart name if chart_url.startswith('oci://'): base_name = chart_url.rstrip('/').split('/')[-1] @@ -42,12 +42,11 @@ def generate_from_helm( if extra_args.strip(): cmd.extend(parse_extra_args(extra_args)) - # Execution + # Run the command and capture output proc = subprocess.run(cmd, check=False, capture_output=True, text=True) stdout_output = proc.stdout or "" stderr_output = proc.stderr or "" - # First we verify if there was an error before file exist has_error = proc.returncode != 0 or has_fatal_error(stdout_output, stderr_output) # Second we verify if there was an error in the stderr output diff --git a/webapp/backend/services/utils.py b/webapp/backend/services/utils.py index 4bce85e..e072f53 100644 --- a/webapp/backend/services/utils.py +++ b/webapp/backend/services/utils.py @@ -1,4 +1,4 @@ -"""Utilitaires pour les services de génération de diagrammes.""" +"""Utilities for diagram generation services.""" import base64 import shlex @@ -6,30 +6,30 @@ from constants import TEXT_FORMATS def has_fatal_error(stdout_txt: str, stderr_txt: str) -> bool: """ - Vérifie si la sortie contient une erreur fatale. - + Check whether subprocess output contains a fatal error marker. + Args: - stdout_txt: Sortie standard - stderr_txt: Sortie d'erreur - + stdout_txt: Standard output text + stderr_txt: Standard error text + Returns: - bool: True si erreur fatale détectée + bool: True if a fatal error was detected """ return ("error:" in (stdout_txt or "").lower()) or ("error:" in (stderr_txt or "").lower()) def parse_extra_args(extra_args: str) -> list[str]: """ - Parse les arguments supplémentaires. - + Parse a string of extra CLI arguments using shell-like tokenization. + Args: - extra_args: Arguments supplémentaires en string - + extra_args: Space-separated argument string (may include quoted tokens) + Returns: - list[str]: Liste des arguments parsés - + list[str]: Parsed argument tokens + Raises: - ValueError: Si les arguments sont invalides + ValueError: If the argument string has invalid shell syntax """ if not extra_args or not extra_args.strip(): return [] @@ -41,15 +41,18 @@ def parse_extra_args(extra_args: str) -> list[str]: def encode_content(content: bytes, output_format: str) -> str: """ - Encode le contenu en base64 ou UTF-8 selon le format. - + Encode diagram content for JSON transport. + + Text-based formats (SVG, DOT, DOT_JSON, DRAWIO) are decoded as UTF-8. + Binary formats (PNG, JPG, PDF) are base64-encoded. + Args: - content: Contenu à encoder - output_format: Format de sortie - + content: Raw file content + output_format: Output format string (e.g. 'png', 'svg') + Returns: - str: Contenu encodé + str: Encoded content ready for the API response """ if output_format in TEXT_FORMATS: return content.decode("utf-8") - return base64.b64encode(content).decode("utf-8") + return base64.b64encode(content).decode("utf-8") \ No newline at end of file diff --git a/webapp/backend/utils/validators.py b/webapp/backend/utils/validators.py index f858adb..f35745d 100644 --- a/webapp/backend/utils/validators.py +++ b/webapp/backend/utils/validators.py @@ -75,7 +75,7 @@ class InputValidator: url: URL of the Helm chart Returns: - Tuple[bool, Optional[str]]: (est_valide, message_erreur) + Tuple[bool, Optional[str]]: (is_valid, error_message) """ if not url or not url.strip(): return False, "Chart URL cannot be empty." @@ -121,7 +121,7 @@ class InputValidator: Tuple[bool, Optional[str]]: (is_valid, error_message) """ if not args or not args.strip(): - return True, None # Les args vides sont valides + return True, None dangerous_chars = [';', '&', '|', '`', '$', '(', ')'] for char in dangerous_chars: diff --git a/webapp/frontend/src/App.jsx b/webapp/frontend/src/App.jsx index e0ca8a9..cf5aa11 100644 --- a/webapp/frontend/src/App.jsx +++ b/webapp/frontend/src/App.jsx @@ -21,7 +21,7 @@ function App() { setRestoredItem(null); }; - // Mémoriser historyContext pour éviter de le recréer à chaque render + // Memoize historyContext to avoid recreating it on every render const historyContext = useMemo( () => ({ addToHistory, getHistoryItem, restoredItem, clearRestoredItem }), [addToHistory, getHistoryItem, restoredItem] diff --git a/webapp/frontend/src/components/common/HistoryPanel.jsx b/webapp/frontend/src/components/common/HistoryPanel.jsx index 7424f2c..5148ab3 100644 --- a/webapp/frontend/src/components/common/HistoryPanel.jsx +++ b/webapp/frontend/src/components/common/HistoryPanel.jsx @@ -120,9 +120,9 @@ const HistoryPanel = ({ history, onRestore, onRemove, onClear, isOpen, onToggle {history.length === 0 ? (
-

Aucun diagramme dans l'historique

+

No diagrams in history

- Les diagrammes générés apparaîtront ici + Generated diagrams will appear here

) : ( diff --git a/webapp/frontend/src/components/common/PanZoomContainer.jsx b/webapp/frontend/src/components/common/PanZoomContainer.jsx index 7dcb97c..b460124 100644 --- a/webapp/frontend/src/components/common/PanZoomContainer.jsx +++ b/webapp/frontend/src/components/common/PanZoomContainer.jsx @@ -14,7 +14,7 @@ export default function PanZoomContainer({ scrollPanSpeed = 3.0, buttonZoomFactor = 1.25, buttonZoomFactorFast = 1.5, - // Souris + // Mouse mouseZoomDampen = 0.018, clampDeltaY = 50, }) { @@ -22,17 +22,17 @@ export default function PanZoomContainer({ const measureRef = useRef(null); const isInControls = (el) => !!(el && el.closest && el.closest('.kd-controls')); - // États affichés + // Displayed state (reactive) const [scale, _setScale] = useState(1); const [tx, _setTx] = useState(0); const [ty, _setTy] = useState(0); - // Réfs calculs + animation + // Refs for calculation and animation (non-reactive) const scaleRef = useRef(1); const txRef = useRef(0); const tyRef = useRef(0); - // Cibles animées + // Animated targets const targetScaleRef = useRef(1); const targetTxRef = useRef(0); const targetTyRef = useRef(0); @@ -55,7 +55,7 @@ export default function PanZoomContainer({ const [naturalSize, setNaturalSize] = useState({ w: 0, h: 0 }); const [vpSize, setVpSize] = useState({ w: 0, h: 0 }); - // Mesures + // Measure natural content size and viewport size useLayoutEffect(() => { const el = measureRef.current; if (!el) return; @@ -83,7 +83,7 @@ export default function PanZoomContainer({ }; }, []); - // Fit initial + // Fit content into viewport on first render useEffect(() => { if (!naturalSize.w || !naturalSize.h || !vpSize.w || !vpSize.h) return; fit(true); @@ -91,7 +91,7 @@ export default function PanZoomContainer({ const clamp = (v, a, b) => Math.min(b, Math.max(a, v)); - // Anime position/zoom vers la cible + // Animate position/zoom toward targets with smoothing const animate = useCallback(() => { const s = scaleRef.current; const tx = txRef.current; @@ -167,7 +167,7 @@ export default function PanZoomContainer({ dY *= vp.clientHeight; } - // --- ZOOM (pinch/ctrl) : adoucir la souris, garder le trackpad tel quel + // --- ZOOM (pinch/ctrl): dampen mouse wheel, keep trackpad as-is if (e.ctrlKey) { const isTrackpad = isTrackpadWheel(e); const sens = isTrackpad ? pinchSensitivity : pinchSensitivity * mouseZoomDampen; @@ -178,7 +178,7 @@ export default function PanZoomContainer({ return; } - // --- Mode "zoom" à la molette : même adoucissement pour souris + // --- Wheel zoom mode: same dampening as pinch/ctrl if (wheelMode === 'zoom') { const isTrackpad = isTrackpadWheel(e); const sens = isTrackpad ? wheelSensitivity : wheelSensitivity * mouseZoomDampen; @@ -189,7 +189,7 @@ export default function PanZoomContainer({ return; } - // --- Par défaut : PAN au wheel/trackpad (deux doigts) + // --- Default: pan with wheel/trackpad (two-finger scroll) const k = scrollPanSpeed; targetTxRef.current = txRef.current - dX * k; targetTyRef.current = tyRef.current - dY * k; diff --git a/webapp/frontend/src/components/common/ProgressBar.jsx b/webapp/frontend/src/components/common/ProgressBar.jsx index c94ab0f..802e948 100644 --- a/webapp/frontend/src/components/common/ProgressBar.jsx +++ b/webapp/frontend/src/components/common/ProgressBar.jsx @@ -9,8 +9,8 @@ const ProgressBar = ({ currentStep = 'idle', isVisible = false }) => { const steps = [ { id: 'parsing', label: 'Parsing' }, { id: 'validation', label: 'Validation' }, - { id: 'generation', label: 'Génération' }, - { id: 'rendering', label: 'Rendu' }, + { id: 'generation', label: 'Generation' }, + { id: 'rendering', label: 'Rendering' }, ]; const getStepStatus = (stepId) => { @@ -65,7 +65,7 @@ const ProgressBar = ({ currentStep = 'idle', isVisible = false }) => { >

- {currentStep === 'completed' ? '✓ Génération terminée' : 'Génération en cours...'} + {currentStep === 'completed' ? '✓ Generation complete' : 'Generation in progress...'}

{currentStep !== 'completed' && currentStep !== 'error' && ( diff --git a/webapp/frontend/src/components/common/Tabs.jsx b/webapp/frontend/src/components/common/Tabs.jsx index 2361480..73b4afe 100644 --- a/webapp/frontend/src/components/common/Tabs.jsx +++ b/webapp/frontend/src/components/common/Tabs.jsx @@ -31,7 +31,7 @@ function Tabs({ historyContext }) { return (
- {/* Onglets */} + {/* Tabs */}
{tabs.map((tab) => ( - {/* Contenu des tabs */} + {/* Tab content */}
{activeTab === 'manifest' && } {activeTab === 'helm' && } diff --git a/webapp/frontend/src/components/tabs/HelmFileTab/index.jsx b/webapp/frontend/src/components/tabs/HelmFileTab/index.jsx index 08d06f9..671d8ff 100644 --- a/webapp/frontend/src/components/tabs/HelmFileTab/index.jsx +++ b/webapp/frontend/src/components/tabs/HelmFileTab/index.jsx @@ -98,7 +98,7 @@ function HelmFileTab({ historyContext }) { historyContext.addToHistory(historyItem); lastHistoryIdRef.current = historyId; } - }, [diagram, progressStep]); // Dépendances minimales pour éviter la boucle + }, [diagram, progressStep]); // minimal deps — avoids a save loop // Restore from history useEffect(() => { diff --git a/webapp/frontend/src/components/tabs/HelmTab/index.jsx b/webapp/frontend/src/components/tabs/HelmTab/index.jsx index be5cc11..d194f78 100644 --- a/webapp/frontend/src/components/tabs/HelmTab/index.jsx +++ b/webapp/frontend/src/components/tabs/HelmTab/index.jsx @@ -93,7 +93,7 @@ function HelmTab({ historyContext }) { historyContext.addToHistory(historyItem); lastHistoryIdRef.current = historyId; } - }, [diagram, progressStep]); // Dépendances minimales pour éviter la boucle + }, [diagram, progressStep]); // minimal deps — avoids a save loop // Restore from history useEffect(() => { @@ -133,7 +133,7 @@ function HelmTab({ historyContext }) { setChartUrl(v); setBackendError(''); - // Valider seulement si l'URL n'est pas vide + // Validate only if URL is not empty if (v && v.trim()) { setInputError( isValidChartUrl(v) diff --git a/webapp/frontend/src/components/tabs/ManifestTab/index.jsx b/webapp/frontend/src/components/tabs/ManifestTab/index.jsx index 029909f..6e3fd48 100644 --- a/webapp/frontend/src/components/tabs/ManifestTab/index.jsx +++ b/webapp/frontend/src/components/tabs/ManifestTab/index.jsx @@ -101,7 +101,7 @@ function ManifestTab({ historyContext }) { historyContext.addToHistory(historyItem); lastHistoryIdRef.current = historyId; } - }, [diagram, progressStep]); // Dépendances minimales pour éviter la boucle + }, [diagram, progressStep]); // minimal deps — avoids a save loop // Restore from history useEffect(() => { diff --git a/webapp/frontend/src/utils/toast.js b/webapp/frontend/src/utils/toast.js index 43af523..81aece7 100644 --- a/webapp/frontend/src/utils/toast.js +++ b/webapp/frontend/src/utils/toast.js @@ -77,9 +77,9 @@ export const dismissToast = (toastId) => { */ export const showPromise = (promise, messages) => { return toast.promise(promise, { - loading: messages.loading || 'Chargement...', - success: messages.success || 'Terminé !', - error: messages.error || 'Une erreur est survenue', + loading: messages.loading || 'Loading...', + success: messages.success || 'Done!', + error: messages.error || 'An error occurred', }); };