[Chore] Translate French comments and UI strings to English

This commit is contained in:
Sadallah
2026-06-10 23:51:08 +02:00
parent e1e84919a4
commit 55df49f6ab
13 changed files with 56 additions and 54 deletions
+2 -2
View File
@@ -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(
+3 -4
View File
@@ -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
+24 -21
View File
@@ -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")
+2 -2
View File
@@ -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:
+1 -1
View File
@@ -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]
@@ -120,9 +120,9 @@ const HistoryPanel = ({ history, onRestore, onRemove, onClear, isOpen, onToggle
{history.length === 0 ? (
<div className="flex flex-col items-center justify-center h-full text-slate-500">
<FileText className="w-16 h-16 mb-4 opacity-50" />
<p className="text-center">Aucun diagramme dans l&apos;historique</p>
<p className="text-center">No diagrams in history</p>
<p className="text-xs text-center mt-2">
Les diagrammes générés apparaîtront ici
Generated diagrams will appear here
</p>
</div>
) : (
@@ -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;
@@ -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 }) => {
>
<div className="flex items-center justify-between mb-4">
<h3 className="text-sm font-semibold text-slate-300">
{currentStep === 'completed' ? '✓ Génération terminée' : 'Génération en cours...'}
{currentStep === 'completed' ? '✓ Generation complete' : 'Generation in progress...'}
</h3>
{currentStep !== 'completed' && currentStep !== 'error' && (
<Loader2 className="w-4 h-4 animate-spin text-blue-400" />
@@ -31,7 +31,7 @@ function Tabs({ historyContext }) {
return (
<div className="flex flex-col flex-1 w-full">
{/* Onglets */}
{/* Tabs */}
<div className="flex mb-4 space-x-4">
{tabs.map((tab) => (
<motion.button
@@ -51,7 +51,7 @@ function Tabs({ historyContext }) {
))}
</div>
{/* Contenu des tabs */}
{/* Tab content */}
<div className="flex-1">
{activeTab === 'manifest' && <ManifestTab historyContext={historyContext} />}
{activeTab === 'helm' && <HelmTab historyContext={historyContext} />}
@@ -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(() => {
@@ -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)
@@ -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(() => {
+3 -3
View File
@@ -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',
});
};