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:
@@ -140,13 +140,13 @@ function DiffView({ diffData }: { diffData: any }) {
|
||||
{pd.positions_opened > 0 && (
|
||||
<div className="text-center">
|
||||
<div className="text-emerald-400 font-bold text-lg">+{pd.positions_opened}</div>
|
||||
<div className="text-[10px] text-slate-500">ouvertes</div>
|
||||
<div className="text-[10px] text-slate-500">opened</div>
|
||||
</div>
|
||||
)}
|
||||
{pd.positions_closed > 0 && (
|
||||
<div className="text-center">
|
||||
<div className="text-red-400 font-bold text-lg">-{pd.positions_closed}</div>
|
||||
<div className="text-[10px] text-slate-500">fermées</div>
|
||||
<div className="text-[10px] text-slate-500">closed</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -159,7 +159,7 @@ function DiffView({ diffData }: { diffData: any }) {
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<Plus className="w-4 h-4 text-emerald-400" />
|
||||
<h3 className="text-sm font-semibold text-emerald-400">
|
||||
Nouvelles positions ({new_positions.length})
|
||||
New positions ({new_positions.length})
|
||||
</h3>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
@@ -170,7 +170,7 @@ function DiffView({ diffData }: { diffData: any }) {
|
||||
<span className="text-slate-400 ml-2">{p.strategy}</span>
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
<span className="text-slate-500">Entrée: {p.entry_price?.toFixed(2) ?? '—'}</span>
|
||||
<span className="text-slate-500">Entry: {p.entry_price?.toFixed(2) ?? '—'}</span>
|
||||
<span className={clsx('font-semibold', (p.pnl_pct ?? 0) >= 0 ? 'text-emerald-400' : 'text-red-400')}>
|
||||
{fmt(p.pnl_pct)}
|
||||
</span>
|
||||
@@ -187,7 +187,7 @@ function DiffView({ diffData }: { diffData: any }) {
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<Minus className="w-4 h-4 text-red-400" />
|
||||
<h3 className="text-sm font-semibold text-red-400">
|
||||
Positions fermées ({closed_positions.length})
|
||||
Closed positions ({closed_positions.length})
|
||||
</h3>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
@@ -198,7 +198,7 @@ function DiffView({ diffData }: { diffData: any }) {
|
||||
<span className="text-slate-500 ml-2">{p.strategy}</span>
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
<span className="text-slate-500">Dernière val.: {fmt(p.pnl_pct)}</span>
|
||||
<span className="text-slate-500">Last val.: {fmt(p.pnl_pct)}</span>
|
||||
<span className={clsx('font-semibold', (p.pnl_pct ?? 0) >= 0 ? 'text-emerald-400' : 'text-red-400')}>
|
||||
{fmtEur(p.pnl_eur)}
|
||||
</span>
|
||||
@@ -213,7 +213,7 @@ function DiffView({ diffData }: { diffData: any }) {
|
||||
{changed_positions.length > 0 && (
|
||||
<div className="bg-dark-800 border border-slate-700/40 rounded-xl p-4">
|
||||
<h3 className="text-sm font-semibold text-white mb-3">
|
||||
Évolution des positions ({changed_positions.length})
|
||||
Position changes ({changed_positions.length})
|
||||
</h3>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-xs">
|
||||
@@ -265,7 +265,7 @@ function SnapshotDetail({ snapId }: { snapId: number }) {
|
||||
staleTime: 300_000,
|
||||
})
|
||||
|
||||
if (isLoading) return <div className="text-slate-600 text-sm p-4">Chargement…</div>
|
||||
if (isLoading) return <div className="text-slate-600 text-sm p-4">Loading…</div>
|
||||
if (!data) return null
|
||||
|
||||
const trades: any[] = data.trades_snapshot ?? []
|
||||
@@ -277,7 +277,7 @@ function SnapshotDetail({ snapId }: { snapId: number }) {
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-white">{fmtDate(data.snapped_at)} UTC</h3>
|
||||
{macro?.dominant && (
|
||||
<span className="text-xs text-slate-500 capitalize">Régime : {macro.dominant}</span>
|
||||
<span className="text-xs text-slate-500 capitalize">Regime: {macro.dominant}</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-4 text-xs">
|
||||
@@ -294,7 +294,7 @@ function SnapshotDetail({ snapId }: { snapId: number }) {
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-slate-500">{data.n_open} ouvertes · {data.n_closed} fermées</span>
|
||||
<span className="text-slate-500">{data.n_open} open · {data.n_closed} closed</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -304,9 +304,9 @@ function SnapshotDetail({ snapId }: { snapId: number }) {
|
||||
<thead>
|
||||
<tr className="text-slate-500 border-b border-slate-700/40">
|
||||
<th className="text-left pb-2 font-medium">Ticker</th>
|
||||
<th className="text-left pb-2 font-medium">Stratégie</th>
|
||||
<th className="text-right pb-2 font-medium">Entrée</th>
|
||||
<th className="text-right pb-2 font-medium">Prix actuel</th>
|
||||
<th className="text-left pb-2 font-medium">Strategy</th>
|
||||
<th className="text-right pb-2 font-medium">Entry</th>
|
||||
<th className="text-right pb-2 font-medium">Current price</th>
|
||||
<th className="text-right pb-2 font-medium">PnL %</th>
|
||||
<th className="text-right pb-2 font-medium">PnL €</th>
|
||||
</tr>
|
||||
@@ -329,7 +329,7 @@ function SnapshotDetail({ snapId }: { snapId: number }) {
|
||||
</tbody>
|
||||
</table>
|
||||
) : (
|
||||
<div className="text-slate-600 text-sm">Aucune position dans ce snapshot</div>
|
||||
<div className="text-slate-600 text-sm">No positions in this snapshot</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
@@ -397,11 +397,11 @@ export default function PositionHistory() {
|
||||
<div>
|
||||
<div className="flex items-center gap-3 mb-1">
|
||||
<History className="w-6 h-6 text-violet-400" />
|
||||
<h1 className="text-xl font-bold text-white">Historique des Positions</h1>
|
||||
<h1 className="text-xl font-bold text-white">Position History</h1>
|
||||
</div>
|
||||
<p className="text-slate-400 text-sm">
|
||||
{snapshots.length} snapshot{snapshots.length !== 1 ? 's' : ''} PnL enregistré{snapshots.length !== 1 ? 's' : ''}
|
||||
{snapshots.length > 0 && ` · de ${fmtDate(snapshots[snapshots.length - 1]?.snapped_at)} à ${fmtDate(snapshots[0]?.snapped_at)}`}
|
||||
{snapshots.length} PnL snapshot{snapshots.length !== 1 ? 's' : ''} recorded
|
||||
{snapshots.length > 0 && ` · from ${fmtDate(snapshots[snapshots.length - 1]?.snapped_at)} to ${fmtDate(snapshots[0]?.snapped_at)}`}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
@@ -412,7 +412,7 @@ export default function PositionHistory() {
|
||||
className={clsx('px-3 py-1.5 rounded text-xs font-semibold transition-colors',
|
||||
viewMode === 'detail' ? 'bg-slate-600 text-white' : 'bg-dark-700 text-slate-400 hover:text-white')}
|
||||
>
|
||||
Détail
|
||||
Detail
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setViewMode('diff')}
|
||||
@@ -428,12 +428,12 @@ export default function PositionHistory() {
|
||||
onClick={() => { setSelectedA(null); setSelectedB(null); setViewMode('detail') }}
|
||||
className="px-3 py-1.5 rounded text-xs text-slate-500 hover:text-slate-300 bg-dark-700"
|
||||
>
|
||||
Effacer sélection
|
||||
Clear selection
|
||||
</button>
|
||||
)}
|
||||
<button onClick={() => refetch()}
|
||||
className="flex items-center gap-1 px-3 py-1.5 rounded text-xs bg-dark-700 text-slate-400 hover:text-white">
|
||||
<RefreshCw className="w-3.5 h-3.5" /> Actualiser
|
||||
<RefreshCw className="w-3.5 h-3.5" /> Refresh
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -448,24 +448,24 @@ export default function PositionHistory() {
|
||||
{/* Selection banner */}
|
||||
{(selectedA || selectedB) && (
|
||||
<div className="flex items-center gap-3 bg-dark-800 border border-slate-700/40 rounded-xl px-4 py-3 text-xs flex-wrap">
|
||||
<span className="text-slate-500">Sélection diff :</span>
|
||||
<span className="text-slate-500">Diff selection:</span>
|
||||
{selectedA ? (
|
||||
<span className="flex items-center gap-1.5 bg-blue-900/30 text-blue-400 border border-blue-700/40 px-2.5 py-1 rounded">
|
||||
<span className="font-bold">A</span>
|
||||
{fmtDate(snapshots.find(s => s.id === selectedA)?.snapped_at ?? '')}
|
||||
</span>
|
||||
) : <span className="text-slate-600">A : non sélectionné</span>}
|
||||
) : <span className="text-slate-600">A: not selected</span>}
|
||||
<ArrowRight className="w-3.5 h-3.5 text-slate-600" />
|
||||
{selectedB ? (
|
||||
<span className="flex items-center gap-1.5 bg-violet-900/30 text-violet-400 border border-violet-700/40 px-2.5 py-1 rounded">
|
||||
<span className="font-bold">B</span>
|
||||
{fmtDate(snapshots.find(s => s.id === selectedB)?.snapped_at ?? '')}
|
||||
</span>
|
||||
) : <span className="text-slate-600">B : non sélectionné</span>}
|
||||
) : <span className="text-slate-600">B: not selected</span>}
|
||||
{canDiff && (
|
||||
<button onClick={() => setViewMode('diff')}
|
||||
className="ml-auto bg-violet-600 hover:bg-violet-500 text-white px-3 py-1 rounded text-xs font-semibold">
|
||||
Voir le diff
|
||||
View diff
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
@@ -475,10 +475,10 @@ export default function PositionHistory() {
|
||||
{!isLoading && snapshots.length === 0 && (
|
||||
<div className="text-center py-20">
|
||||
<History className="w-14 h-14 text-slate-700 mx-auto mb-4" />
|
||||
<div className="text-slate-400 font-semibold mb-2">Aucun snapshot PnL disponible</div>
|
||||
<div className="text-slate-400 font-semibold mb-2">No PnL snapshots available</div>
|
||||
<p className="text-slate-600 text-sm max-w-md mx-auto">
|
||||
Activez le Scheduler PnL dans la Configuration ou déclenchez un snapshot manuellement
|
||||
depuis la page Configuration → Auto-Cycle & Logging.
|
||||
Enable the PnL Scheduler in Configuration or trigger a snapshot manually
|
||||
from the Configuration → Auto-Cycle & Logging page.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
@@ -491,7 +491,7 @@ export default function PositionHistory() {
|
||||
{/* Mini sparkline */}
|
||||
{sparkData.length > 2 && (
|
||||
<div className="bg-dark-800 border border-slate-700/40 rounded-xl p-3">
|
||||
<div className="text-xs text-slate-500 mb-2">PnL portfolio dans le temps</div>
|
||||
<div className="text-xs text-slate-500 mb-2">Portfolio PnL over time</div>
|
||||
<ResponsiveContainer width="100%" height={80}>
|
||||
<LineChart data={sparkData} margin={{ top: 4, right: 4, left: -30, bottom: 0 }}>
|
||||
<XAxis dataKey="date" hide />
|
||||
@@ -507,7 +507,7 @@ export default function PositionHistory() {
|
||||
{/* Snapshot list */}
|
||||
<div className="bg-dark-800 border border-slate-700/40 rounded-xl p-3 space-y-1.5 max-h-[calc(100vh-320px)] overflow-y-auto">
|
||||
<div className="text-[10px] text-slate-600 uppercase tracking-wider px-1 mb-2">
|
||||
{snapshots.length} snapshots — cliquez pour détail · A/B pour diff
|
||||
{snapshots.length} snapshots — click for detail · A/B to diff
|
||||
</div>
|
||||
{snapshots.map(s => (
|
||||
<div key={s.id} onClick={() => { setActiveDetail(s.id); setViewMode('detail') }}>
|
||||
@@ -527,7 +527,7 @@ export default function PositionHistory() {
|
||||
<div className="lg:col-span-2">
|
||||
{viewMode === 'diff' && canDiff && (
|
||||
diffLoading
|
||||
? <div className="text-slate-500 text-sm p-4">Calcul du diff…</div>
|
||||
? <div className="text-slate-500 text-sm p-4">Computing diff…</div>
|
||||
: diffError
|
||||
? <div className="text-red-400 text-sm p-4">{String(diffError)}</div>
|
||||
: diffData ? <DiffView diffData={diffData} />
|
||||
@@ -542,8 +542,8 @@ export default function PositionHistory() {
|
||||
<div className="flex flex-col items-center justify-center py-20 text-center">
|
||||
<TrendingUp className="w-12 h-12 text-slate-700 mb-4" />
|
||||
<div className="text-slate-500 text-sm">
|
||||
Cliquez sur un snapshot pour voir le détail<br />
|
||||
ou sélectionnez A et B pour comparer deux valuations
|
||||
Click a snapshot to see the detail<br />
|
||||
or select A and B to compare two valuations
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -552,7 +552,7 @@ export default function PositionHistory() {
|
||||
<div className="flex flex-col items-center justify-center py-20 text-center">
|
||||
<TrendingDown className="w-12 h-12 text-slate-700 mb-4" />
|
||||
<div className="text-slate-500 text-sm">
|
||||
Sélectionnez deux snapshots (A et B) depuis la liste pour voir le diff
|
||||
Select two snapshots (A and B) from the list to view the diff
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user