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
+22 -20
View File
@@ -4,6 +4,7 @@ import { SearchAwardReferences, GetAwardDefs, GetAwardReferenceMeta } from '../.
import {
Select, SelectTrigger, SelectValue, SelectContent, SelectItem,
} from '@/components/ui/select';
import { useI18n } from '@/lib/i18n';
type AwardRef = { code: string; name: string; dxcc: number; group: string; subgrp: string };
type AwardDef = { code: string; name: string; field?: string; dxcc_filter?: number[] | null; dynamic?: boolean };
@@ -36,6 +37,7 @@ interface Props {
}
export function AwardRefSelector({ dxcc, value, onChange, fieldValues, heightClass = 'h-[210px]' }: Props) {
const { t } = useI18n();
const [defs, setDefs] = useState<AwardDef[]>([]);
const [metas, setMetas] = useState<Record<string, Meta>>({});
const [awardCode, setAwardCode] = useState('POTA');
@@ -208,9 +210,9 @@ export function AwardRefSelector({ dxcc, value, onChange, fieldValues, heightCla
{/* Group / Sub from selected ref */}
<div className="grid grid-cols-[38px_1fr] items-center gap-x-1.5 gap-y-0.5 text-xs">
<span className="text-muted-foreground text-[11px]">Group</span>
<span className="text-muted-foreground text-[11px]">{t('awrs.group')}</span>
<span className="font-mono truncate text-[11px]">{selectedRef?.group || '—'}</span>
<span className="text-muted-foreground text-[11px]">Sub</span>
<span className="text-muted-foreground text-[11px]">{t('awrs.sub')}</span>
<span className="font-mono truncate text-[11px]">{selectedRef?.subgrp || '—'}</span>
</div>
@@ -225,7 +227,7 @@ export function AwardRefSelector({ dxcc, value, onChange, fieldValues, heightCla
</div>
) : (
<div className="h-6 flex items-center px-2 text-[11px] text-muted-foreground italic border border-dashed border-border rounded">
pick a reference
{t('awrs.pickReference')}
</div>
)}
@@ -236,10 +238,10 @@ export function AwardRefSelector({ dxcc, value, onChange, fieldValues, heightCla
onClick={() => selectedRef && addRef(selectedRef)}
className="flex items-center gap-1 h-6 px-2 text-xs rounded border border-border hover:bg-accent disabled:opacity-40 disabled:cursor-not-allowed"
>
<Plus className="size-3" />Add
<Plus className="size-3" />{t('awrs.add')}
</button>
<span className="text-[11px] text-muted-foreground">
{dxcc ? `DXCC #${dxcc}` : 'Enter a callsign first'}
{dxcc ? `DXCC #${dxcc}` : t('awrs.enterCallsignFirst')}
</span>
</div>
@@ -248,7 +250,7 @@ export function AwardRefSelector({ dxcc, value, onChange, fieldValues, heightCla
{/* Added refs list */}
<div className="flex-1 overflow-auto space-y-0.5 min-h-0">
{entries.length === 0 ? (
<p className="text-[11px] text-muted-foreground italic py-0.5">No references added yet</p>
<p className="text-[11px] text-muted-foreground italic py-0.5">{t('awrs.noRefsAdded')}</p>
) : (
entries.map((entry) => (
<div
@@ -273,7 +275,7 @@ export function AwardRefSelector({ dxcc, value, onChange, fieldValues, heightCla
{/* Right panel: reference search */}
<div className="w-[172px] shrink-0 flex flex-col gap-1.5 border-l pl-2 min-w-0">
<span className="text-xs font-semibold">References</span>
<span className="text-xs font-semibold">{t('awrs.references')}</span>
{/* Auto-match from the QSO field (e.g. State NB → RAC@NB). */}
{autoMatch && (
<button
@@ -285,17 +287,17 @@ export function AwardRefSelector({ dxcc, value, onChange, fieldValues, heightCla
? 'border-emerald-300 bg-emerald-50 text-emerald-800 cursor-default'
: 'border-emerald-300 bg-emerald-50/60 text-emerald-800 hover:bg-emerald-100'
}`}
title={`The ${selField.toUpperCase()} field is ${autoMatch.code} — this award counts it automatically`}
title={t('awrs.autoMatchTitle', { field: selField.toUpperCase(), code: autoMatch.code })}
>
{autoAlreadyAdded ? '✓ ' : '+ '}
<span className="font-mono font-semibold">{autoMatch.code}</span>
<span className="text-emerald-700"> from {selField}</span>
{!autoAlreadyAdded && <span className="block text-[10px] text-emerald-700/80">auto click to add</span>}
<span className="text-emerald-700"> {t('awrs.fromField', { field: selField })}</span>
{!autoAlreadyAdded && <span className="block text-[10px] text-emerald-700/80">{t('awrs.autoClickToAdd')}</span>}
</button>
)}
<input
className="h-6 w-full rounded border border-input bg-background px-2 text-xs focus:outline-none focus:ring-1 focus:ring-ring"
placeholder="Search…"
placeholder={t('awrs.search')}
value={q}
onChange={(e) => setQ(e.target.value)}
/>
@@ -306,22 +308,22 @@ export function AwardRefSelector({ dxcc, value, onChange, fieldValues, heightCla
type="button"
onClick={() => { addRef({ code: q.trim().toUpperCase(), name: '' } as AwardRef); setQ(''); }}
className="text-left rounded border border-dashed border-primary/50 px-1.5 py-1 text-[11px] text-primary hover:bg-primary/10"
title="Add this reference even though it isn't in the list yet (new / unlisted)"
title={t('awrs.addUnlistedTitle')}
>
+ Add <span className="font-mono font-semibold">{q.trim().toUpperCase()}</span>
<span className="text-[10px] text-muted-foreground"> (unlisted)</span>
{t('awrs.addPrefix')} <span className="font-mono font-semibold">{q.trim().toUpperCase()}</span>
<span className="text-[10px] text-muted-foreground"> {t('awrs.unlisted')}</span>
</button>
)}
<div className="flex-1 overflow-auto border rounded-md text-xs min-h-0">
{busy && (
<div className="flex items-center gap-1.5 px-2 py-1.5 text-muted-foreground">
<Loader2 className="size-3 animate-spin" />Searching
<Loader2 className="size-3 animate-spin" />{t('awrs.searching')}
</div>
)}
{/* Too many auto-results → require typed search */}
{!busy && q.length < 2 && tooManyAuto && (
<div className="px-2 py-1.5 text-[11px] text-muted-foreground leading-snug">
Type 2+ chars to search
{t('awrs.typeToSearch')}
</div>
)}
{/* Empty short-query state: prompt for a callsign (dynamic lists) or
@@ -329,16 +331,16 @@ export function AwardRefSelector({ dxcc, value, onChange, fieldValues, heightCla
{!busy && q.length < 2 && !tooManyAuto && autoResults.length === 0 && (
<div className="px-2 py-1.5 text-[11px] text-muted-foreground leading-snug">
{isDynamic && !dxcc
? 'Enter a callsign, or type to search.'
: 'No references for this entity.'}
? t('awrs.enterCallsignOrSearch')
: t('awrs.noRefsForEntity')}
</div>
)}
{/* Typed search, no results */}
{!busy && q.length >= 2 && results.length === 0 && (
<div className="px-2 py-2 text-[11px] text-muted-foreground leading-snug">
No results.
{t('awrs.noResults')}
<br />
<span className="text-[10px]">Download reference lists in the Awards panel Import data.</span>
<span className="text-[10px]">{t('awrs.downloadLists')}</span>
</div>
)}
{results.map((r) => (