feat: translate all UI strings to English for international release

Complete French→English translation across all frontend pages and backend
services — every label, button, header, empty state, toast, and nav item
is now in English. Build verified clean (tsc + vite). No i18n library
added; direct string replacement throughout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OpenSquared
2026-06-22 09:06:37 +02:00
parent f8a0a6d023
commit dcbc9f19fc
24 changed files with 1443 additions and 1444 deletions

View File

@@ -11,8 +11,8 @@ function BayesianTable({ data }: { data: any[] }) {
return (
<div className="text-center py-10 text-slate-500">
<Brain className="w-8 h-8 mx-auto mb-2 opacity-20" />
<div>Pas encore de données bayésiennes</div>
<div className="text-xs mt-1">Les posteriors se calculent après des trades matures (35% de l'horizon)</div>
<div>No Bayesian data yet</div>
<div className="text-xs mt-1">Posteriors are computed after mature trades (35% of the horizon)</div>
</div>
)
}
@@ -29,11 +29,11 @@ function BayesianTable({ data }: { data: any[] }) {
<tr className="text-slate-500 border-b border-slate-700/30">
<th className="text-left py-2 pr-3 font-medium">Pattern</th>
<th className="text-right py-2 px-2 font-medium">Prior GPT</th>
<th className="text-right py-2 px-2 font-medium">WR Bayésien</th>
<th className="text-right py-2 px-2 font-medium">IC 95%</th>
<th className="text-right py-2 px-2 font-medium">Trades matures</th>
<th className="text-right py-2 px-2 font-medium">Dérive</th>
<th className="text-center py-2 px-2 font-medium">Confiance</th>
<th className="text-right py-2 px-2 font-medium">Bayesian WR</th>
<th className="text-right py-2 px-2 font-medium">CI 95%</th>
<th className="text-right py-2 px-2 font-medium">Mature trades</th>
<th className="text-right py-2 px-2 font-medium">Drift</th>
<th className="text-center py-2 px-2 font-medium">Confidence</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-800/50">
@@ -78,7 +78,7 @@ function BayesianTable({ data }: { data: any[] }) {
)}
{withoutData.length > 0 && (
<div className="text-xs text-slate-600 mt-1">
{withoutData.length} pattern(s) sans trades matures — prior GPT uniquement
{withoutData.length} pattern(s) without mature trades GPT prior only
</div>
)}
</div>
@@ -92,8 +92,8 @@ function TransitionMatrix({ data }: { data: any }) {
return (
<div className="text-center py-8 text-slate-500">
<GitBranch className="w-8 h-8 mx-auto mb-2 opacity-20" />
<div>Pas encore de transitions détectées</div>
<div className="text-xs mt-1">Les clusters se remplissent au fil des cycles</div>
<div>No transitions detected yet</div>
<div className="text-xs mt-1">Clusters fill up as cycles run</div>
</div>
)
}
@@ -104,13 +104,13 @@ function TransitionMatrix({ data }: { data: any }) {
return (
<div className="overflow-x-auto">
<div className="text-xs text-slate-500 mb-2">
Probabilité de transition d'un régime à l'autre (lignes = source, colonnes = destination)
· {data.n_transitions} transitions totales
Transition probability from one regime to another (rows = source, columns = destination)
· {data.n_transitions} total transitions
</div>
<table className="text-xs border-collapse">
<thead>
<tr>
<th className="text-slate-500 p-2 font-normal text-right pr-3">De ↓ / Vers →</th>
<th className="text-slate-500 p-2 font-normal text-right pr-3">From / To </th>
{ids.map(dst => (
<th key={dst} className="p-2 font-medium text-slate-300 text-center min-w-[90px]">
<div className="text-[10px] text-slate-500">C{dst}</div>
@@ -145,7 +145,7 @@ function TransitionMatrix({ data }: { data: any }) {
</tbody>
</table>
<div className="text-[10px] text-slate-600 mt-2">
Diagonal = reste dans le même cluster · Vert = transition dominante · Bleu = auto-transition
Diagonal = stays in same cluster · Green = dominant transition · Blue = self-transition
</div>
</div>
)
@@ -165,7 +165,7 @@ function ClusterTimeline({ data }: { data: any[] }) {
if (!data || data.length === 0) {
return (
<div className="text-center py-6 text-slate-500 text-xs">
Aucun cluster détecté encore — lancez un cycle pour démarrer
No cluster detected yet run a cycle to get started
</div>
)
}
@@ -187,7 +187,7 @@ function ClusterTimeline({ data }: { data: any[] }) {
{recent.map((r: any, i: number) => (
<div
key={i}
title={`${r.timestamp?.slice(0, 16)} · ${r.cluster_label} · ${r.dominant_regime}${r.anomaly_flag ? ' anomalie' : ''}`}
title={`${r.timestamp?.slice(0, 16)} · ${r.cluster_label} · ${r.dominant_regime}${r.anomaly_flag ? ' ⚠️ anomaly' : ''}`}
className={clsx(
'w-5 h-5 rounded cursor-default',
CLUSTER_COLORS[r.cluster_id] ?? 'bg-slate-600',
@@ -197,20 +197,20 @@ function ClusterTimeline({ data }: { data: any[] }) {
))}
</div>
<div className="text-[10px] text-slate-600">
Chaque carré = 1 snapshot · Blanc cerclé = anomalie détectée · {data.length} entrées au total
Each square = 1 snapshot · White ring = anomaly detected · {data.length} total entries
</div>
{/* Latest cluster detail */}
{data[0] && (
<div className="mt-3 p-3 rounded bg-dark-700/60 border border-slate-700/30 text-xs">
<div className="text-slate-400 mb-1">Cluster actuel</div>
<div className="text-slate-400 mb-1">Current cluster</div>
<div className="flex items-center gap-2">
<span className={clsx('w-3 h-3 rounded-full', CLUSTER_COLORS[data[0].cluster_id])} />
<span className="text-white font-semibold">{data[0].cluster_label}</span>
<span className="text-slate-500">({data[0].dominant_regime})</span>
{data[0].anomaly_flag ? (
<span className="flex items-center gap-1 text-amber-400 font-bold">
<AlertTriangle className="w-3 h-3" /> Anomalie
<AlertTriangle className="w-3 h-3" /> Anomaly
</span>
) : null}
</div>
@@ -228,21 +228,21 @@ function EmbeddingsSummary({ data }: { data: any[] }) {
return (
<div className="text-center py-6 text-slate-500 text-xs">
<Cpu className="w-6 h-6 mx-auto mb-1 opacity-20" />
Aucun embedding disponible — ils se génèrent automatiquement lors du filtrage des patterns
No embeddings available they are generated automatically during pattern filtering
</div>
)
}
return (
<div className="space-y-2">
<div className="text-xs text-slate-500">{data.length} patterns vectorisés</div>
<div className="text-xs text-slate-500">{data.length} vectorized patterns</div>
<div className="overflow-x-auto">
<table className="w-full text-xs">
<thead>
<tr className="text-slate-500 border-b border-slate-700/30">
<th className="text-left py-1.5 pr-3 font-medium">Pattern</th>
<th className="text-left py-1.5 px-2 font-medium">Classe</th>
<th className="text-right py-1.5 px-2 font-medium">Modèle</th>
<th className="text-right py-1.5 px-2 font-medium">Mis à jour</th>
<th className="text-left py-1.5 px-2 font-medium">Class</th>
<th className="text-right py-1.5 px-2 font-medium">Model</th>
<th className="text-right py-1.5 px-2 font-medium">Updated</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-800/30">
@@ -301,10 +301,10 @@ export default function AnalyticsAdvanced() {
<div className="flex items-start justify-between gap-4">
<div>
<h1 className="text-xl font-bold text-white flex items-center gap-2">
<Brain className="w-5 h-5 text-purple-400" /> Analytics Avancées — Phase 4
<Brain className="w-5 h-5 text-purple-400" /> Advanced Analytics Phase 4
</h1>
<p className="text-xs text-slate-500 mt-0.5">
Bayesian updating · Clustering de régimes · Embeddings sémantiques
Bayesian updating · Regime clustering · Semantic embeddings
</p>
</div>
<div className="flex gap-2">
@@ -322,7 +322,7 @@ export default function AnalyticsAdvanced() {
className="flex items-center gap-1.5 px-3 py-1.5 text-xs bg-blue-600/20 hover:bg-blue-600/30 border border-blue-500/30 text-blue-300 rounded transition-colors disabled:opacity-50"
>
<RefreshCw className={clsx('w-3 h-3', regimeDetect.isPending && 'animate-spin')} />
tecter régime
Detect regime
</button>
</div>
</div>
@@ -333,25 +333,25 @@ export default function AnalyticsAdvanced() {
<div className="text-2xl font-bold text-purple-400 font-mono">
{patternsWithData.length}
</div>
<div className="text-xs text-slate-500 mt-1">Patterns bayésiens actifs</div>
<div className="text-xs text-slate-500 mt-1">Active Bayesian patterns</div>
</div>
<div className="card">
<div className="text-2xl font-bold text-white font-mono">
{avgBayesWR !== null ? `${avgBayesWR}%` : '—'}
</div>
<div className="text-xs text-slate-500 mt-1">Win rate bayésien moyen</div>
<div className="text-xs text-slate-500 mt-1">Average Bayesian win rate</div>
</div>
<div className="card">
<div className={clsx('text-2xl font-bold font-mono', latestCluster ? CLUSTER_COLORS[latestCluster.cluster_id]?.replace('bg-', 'text-') ?? 'text-slate-400' : 'text-slate-500')}>
{latestCluster ? `C${latestCluster.cluster_id}` : '—'}
</div>
<div className="text-xs text-slate-500 mt-1">
{latestCluster?.cluster_label ?? 'Aucun cluster'}
{latestCluster?.cluster_label ?? 'No cluster'}
</div>
</div>
<div className="card">
<div className="text-2xl font-bold text-blue-400 font-mono">{embeddings.length}</div>
<div className="text-xs text-slate-500 mt-1">Patterns vectorisés</div>
<div className="text-xs text-slate-500 mt-1">Vectorized patterns</div>
</div>
</div>
@@ -360,8 +360,8 @@ export default function AnalyticsAdvanced() {
<div className="flex items-center justify-between mb-3">
<div className="text-sm font-semibold text-white flex items-center gap-2">
<Brain className="w-4 h-4 text-purple-400" />
Posteriors bayésiens par pattern
<span className="text-xs text-slate-500 font-normal">Beta(α,β) · IC 95%</span>
Bayesian posteriors by pattern
<span className="text-xs text-slate-500 font-normal">Beta(α,β) · CI 95%</span>
</div>
{bayesUpdate.data && (
<span className="text-xs text-emerald-400">{bayesUpdate.data.message}</span>
@@ -374,9 +374,9 @@ export default function AnalyticsAdvanced() {
)}
<div className="mt-3 p-3 bg-dark-700/40 rounded text-xs text-slate-500 border border-slate-700/20">
<strong className="text-slate-400">Lecture :</strong> Prior GPT = probabilité annoncée par GPT-4o ·
WR Bayésien = win rate observé avec lissage Laplace (β a priori faible) ·
Dérive = écart posterior prior · IC 95% basé sur la distribution Beta
<strong className="text-slate-400">Reading:</strong> GPT Prior = probability stated by GPT-4o ·
Bayesian WR = observed win rate with Laplace smoothing (weak β prior) ·
Drift = posterior prior gap · CI 95% based on Beta distribution
</div>
</div>
@@ -387,16 +387,16 @@ export default function AnalyticsAdvanced() {
<div className="flex items-center justify-between mb-3">
<div className="text-sm font-semibold text-white flex items-center gap-2">
<Layers className="w-4 h-4 text-blue-400" />
Historique des clusters
Cluster history
</div>
<select
value={regimeDays}
onChange={e => setRegimeDays(Number(e.target.value))}
className="bg-dark-700 border border-slate-700 rounded px-2 py-1 text-xs text-slate-300"
>
<option value={30}>30 jours</option>
<option value={90}>90 jours</option>
<option value={180}>180 jours</option>
<option value={30}>30 days</option>
<option value={90}>90 days</option>
<option value={180}>180 days</option>
</select>
</div>
{loadingClusters ? (
@@ -410,8 +410,8 @@ export default function AnalyticsAdvanced() {
<div className="card">
<div className="text-sm font-semibold text-white flex items-center gap-2 mb-3">
<GitBranch className="w-4 h-4 text-blue-400" />
Matrice de transition
<span className="text-xs text-slate-500 font-normal">P(régime j | régime i)</span>
Transition matrix
<span className="text-xs text-slate-500 font-normal">P(regime j | regime i)</span>
</div>
{loadingTrans ? (
<div className="h-32 bg-dark-700 animate-pulse rounded" />
@@ -425,9 +425,9 @@ export default function AnalyticsAdvanced() {
<div className="card">
<div className="text-sm font-semibold text-white flex items-center gap-2 mb-3">
<Cpu className="w-4 h-4 text-emerald-400" />
Embeddings sémantiques
Semantic embeddings
<span className="text-xs text-slate-500 font-normal">
text-embedding-3-small · Similarité cosinus remplace Jaccard
text-embedding-3-small · Cosine similarity replaces Jaccard
</span>
</div>
{loadingEmb ? (
@@ -436,9 +436,9 @@ export default function AnalyticsAdvanced() {
<EmbeddingsSummary data={embeddings} />
)}
<div className="mt-3 p-3 bg-dark-700/40 rounded text-xs text-slate-500 border border-slate-700/20">
<strong className="text-slate-400">Comment ça marche :</strong> Chaque nouveau pattern suggéré est vectori et comparé
aux patterns existants via similarité cosinus (seuil : 0.75). Si la similarité est &gt; 0.75,
le pattern est reje comme doublon sémantique plus précis que Jaccard qui ne voit que les mots communs.
<strong className="text-slate-400">How it works:</strong> Each newly suggested pattern is vectorized and compared
to existing patterns via cosine similarity (threshold: 0.75). If similarity is &gt; 0.75,
the pattern is rejected as a semantic duplicate more precise than Jaccard which only sees common words.
</div>
</div>
</div>