feat: Complete translation in French

This commit is contained in:
2026-07-05 10:44:40 +02:00
parent 3a6afc28ac
commit 2d742be7df
32 changed files with 1841 additions and 1421 deletions
+16 -13
View File
@@ -8,6 +8,7 @@ import {
IcomSetScope, IcomScopeData, IcomSetScopeMode, GetCATState, SetCATFrequency,
} from '../../wailsjs/go/main/App';
import { cn } from '@/lib/utils';
import { useI18n } from '@/lib/i18n';
type IcomState = {
available: boolean; model?: string; mode?: string;
@@ -151,6 +152,7 @@ function sUnit(v: number): string {
// reassembled sweep on a canvas. The amplitude array is raw rig scale (~0-160);
// we normalise to the tallest recent peak so the trace fills the height.
function ScopePanadapter() {
const { t } = useI18n();
const [on, setOn] = useState(false);
const [fixed, setFixed] = useState(true);
const canvasRef = useRef<HTMLCanvasElement>(null);
@@ -288,10 +290,10 @@ function ScopePanadapter() {
};
return (
<Card icon={Activity} title="Spectrum" accent="#38bdf8">
<Card icon={Activity} title={t('icmp.spectrum')} accent="#38bdf8">
<div className="flex items-center justify-between gap-2">
<span className="text-[11px] text-muted-foreground truncate">
{on ? (fixed ? 'Fixed — double-click / wheel to tune' : 'Center — follows VFO') : 'Scope off'}
{on ? (fixed ? t('icmp.scopeFixed') : t('icmp.scopeCenter')) : t('icmp.scopeOff')}
</span>
<div className="flex items-center gap-2 shrink-0">
{on && (
@@ -314,6 +316,7 @@ function ScopePanadapter() {
// read every cache cycle; DSP set-controls are optimistic and reconcile on the
// next poll. Front-panel knob changes for DSP show after ↻ Refresh.
export function IcomPanel() {
const { t } = useI18n();
const [st, setSt] = useState<IcomState>(ZERO);
const [busy, setBusy] = useState(false);
const [tuning, setTuning] = useState(false);
@@ -355,7 +358,7 @@ export function IcomPanel() {
if (!st.available) {
return (
<div className="h-full flex items-center justify-center text-sm text-muted-foreground p-6 text-center">
Icom not connected. Enable the Icom CI-V backend in Settings CAT and connect the radio's USB port.
{t('icmp.notConnected')}
</div>
);
}
@@ -379,7 +382,7 @@ export function IcomPanel() {
</div>
<button type="button" onClick={refresh} disabled={busy}
className="inline-flex items-center gap-1.5 rounded-md border border-border bg-card px-2 py-1 text-xs hover:bg-muted disabled:opacity-40">
<RefreshCw className={cn('size-3.5', busy && 'animate-spin')} /> Refresh
<RefreshCw className={cn('size-3.5', busy && 'animate-spin')} /> {t('icmp.refresh')}
</button>
</div>
@@ -388,7 +391,7 @@ export function IcomPanel() {
<div className="grid grid-cols-1 lg:grid-cols-2 gap-3">
{/* Live meters. */}
<Card icon={Zap} title="Meters" accent="#f59e0b">
<Card icon={Zap} title={t('icmp.meters')} accent="#f59e0b">
{tx ? (
<>
<Meter label="Po" value={st.power_meter} accent="#ef4444" scale={`${st.power_meter}%`} />
@@ -400,12 +403,12 @@ export function IcomPanel() {
</Card>
{/* Transmit controls. */}
<Card icon={Mic} title="Transmit" accent="#ef4444">
<Row label="Power">
<Card icon={Mic} title={t('icmp.transmit')} accent="#ef4444">
<Row label={t('icmp.power')}>
<Slider value={st.rf_power} accent="#ef4444" onChange={(v) => set({ rf_power: v }, () => IcomSetRFPower(v))} />
<span className="w-8 text-right text-xs font-mono tabular-nums text-muted-foreground">{st.rf_power}</span>
</Row>
<Row label="Mic">
<Row label={t('icmp.mic')}>
<Slider value={st.mic_gain} accent="#ef4444" onChange={(v) => set({ mic_gain: v }, () => IcomSetMicGain(v))} />
<span className="w-8 text-right text-xs font-mono tabular-nums text-muted-foreground">{st.mic_gain}</span>
</Row>
@@ -424,7 +427,7 @@ export function IcomPanel() {
</div>
</Card>
<Card icon={Radio} title="Receive" accent="#2563eb">
<Card icon={Radio} title={t('icmp.receive')} accent="#2563eb">
<Row label="AF">
<Slider value={st.af_gain} onChange={(v) => set({ af_gain: v }, () => IcomSetAFGain(v))} />
<span className="w-8 text-right text-xs font-mono tabular-nums text-muted-foreground">{st.af_gain}</span>
@@ -437,7 +440,7 @@ export function IcomPanel() {
<Segmented value={st.agc || ''} options={[{ v: 'FAST', l: 'FAST' }, { v: 'MID', l: 'MID' }, { v: 'SLOW', l: 'SLOW' }]}
onChange={(v) => set({ agc: v }, () => IcomSetAGC(v))} />
</Row>
<Row label="Preamp">
<Row label={t('icmp.preamp')}>
<Segmented value={String(st.preamp)} options={[{ v: '0', l: 'OFF' }, { v: '1', l: 'P1' }, { v: '2', l: 'P2' }]}
onChange={(v) => set({ preamp: parseInt(v) }, () => IcomSetPreamp(parseInt(v)))} />
</Row>
@@ -445,13 +448,13 @@ export function IcomPanel() {
<Segmented value={String(st.att)} options={[{ v: '0', l: 'OFF' }, { v: '6', l: '6dB' }, { v: '12', l: '12dB' }, { v: '18', l: '18dB' }]}
onChange={(v) => set({ att: parseInt(v) }, () => IcomSetAtt(parseInt(v)))} />
</Row>
<Row label="Filter">
<Row label={t('icmp.filter')}>
<Segmented value={String(st.filter)} options={[{ v: '1', l: 'FIL1' }, { v: '2', l: 'FIL2' }, { v: '3', l: 'FIL3' }]}
onChange={(v) => set({ filter: parseInt(v) }, () => IcomSetFilter(parseInt(v)))} />
</Row>
</Card>
<Card icon={AudioLines} title="Noise / Notch" accent="#16a34a">
<Card icon={AudioLines} title={t('icmp.noiseNotch')} accent="#16a34a">
<LevelRow label="NB" on={st.nb} value={st.nb_level}
onToggle={() => set({ nb: !st.nb }, () => IcomSetNB(!st.nb))}
onLevel={(v) => set({ nb_level: v }, () => IcomSetNBLevel(v))} />
@@ -460,7 +463,7 @@ export function IcomPanel() {
onLevel={(v) => set({ nr_level: v }, () => IcomSetNRLevel(v))} />
<div className="flex items-center gap-2">
<Chip label="ANF" on={st.anf} onClick={() => set({ anf: !st.anf }, () => IcomSetANF(!st.anf))} />
<span className="text-xs text-muted-foreground">Auto notch filter</span>
<span className="text-xs text-muted-foreground">{t('icmp.autoNotch')}</span>
</div>
</Card>
</div>