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:
@@ -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')} />
|
||||
Dé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 vectorisé et comparé
|
||||
aux patterns existants via similarité cosinus (seuil : 0.75). Si la similarité est > 0.75,
|
||||
le pattern est rejeté 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 > 0.75,
|
||||
the pattern is rejected as a semantic duplicate — more precise than Jaccard which only sees common words.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user