fix(sat,rda): the dropdown reads the live list, and the RDA buttons answer

SATELLITES: the field read the list once, when the details panel first
mounted — which is at startup. A list saved in Preferences afterwards
therefore did nothing until a restart. It comes from App now, which
already reloads the lists when Preferences close.

RDA COMPARE: a failed comparison wrote its error into the message beside
the FILL DISTRICTS button, a row above — the error appeared under a
button nobody had pressed while the one that had been pressed showed
nothing, which reads as 'the button does nothing'. It has its own message
now, and reports the two results that look like silence: no disagreement
at all, and no Russian contacts to compare. Both buttons say what they
are doing while they do it, and the comparison logs before it starts
reading — on a remote MySQL that read is seconds of quiet.
This commit is contained in:
2026-08-25 19:53:30 +02:00
parent e41a3a4c1c
commit 67c85be23c
6 changed files with 45 additions and 20 deletions
+7
View File
@@ -488,6 +488,11 @@ export default function App() {
const { t, lang } = useI18n();
// === Lists from settings (fallback for first paint) ===
const [bands, setBands] = useState<string[]>(DEFAULT_BANDS);
// The station's satellites, for the entry form's SAT_NAME dropdown. Held HERE
// and not inside the panel: loadLists() already runs when Preferences close,
// so a list edited there reaches the field without a restart — which is what
// a panel reading it once at mount could not do.
const [satellites, setSatellites] = useState<string[]>([]);
const [modes, setModes] = useState<string[]>(DEFAULT_MODES);
const modesRef = useRef(modes);
useEffect(() => { modesRef.current = modes; }, [modes]);
@@ -3081,6 +3086,7 @@ export default function App() {
const l: ListsSettings = await GetListsSettings();
setRstLists({ phone: (l as any).rst_phone ?? [], cw: (l as any).rst_cw ?? [], digital: (l as any).rst_digital ?? [] });
if (l.bands && l.bands.length) setBands(l.bands);
setSatellites([...(((l as any).satellites ?? []) as string[])].filter(Boolean).sort());
if (l.modes && l.modes.length) {
setModePresets(l.modes);
const names = l.modes.map((m) => m.name);
@@ -7051,6 +7057,7 @@ export default function App() {
band={band}
mode={mode}
bands={bands}
satellites={satellites}
onEditQso={openEdit}
{...(!callsign.trim() && selQso ? {
slotCall: selQso.call, slotBand: selQso.band, slotMode: selQso.mode,
+6 -11
View File
@@ -1,5 +1,5 @@
import { useEffect, useMemo, useState } from 'react';
import { ComputeQSOAwardRefs, IsNewUSCounty, GetListsSettings } from '../../wailsjs/go/main/App';
import { ComputeQSOAwardRefs, IsNewUSCounty } from '../../wailsjs/go/main/App';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Checkbox } from '@/components/ui/checkbox';
@@ -71,6 +71,10 @@ interface Props {
band: string;
mode: string;
bands?: string[]; // configured bands for the worked-before matrix columns
// The station's satellites, for the SAT_NAME dropdown. Passed in rather than
// read here: the list lives in Preferences, and App already reloads it when
// Preferences close — a panel reading it once at mount would need a restart.
satellites?: string[];
// When the entry form is empty and a QSO is selected in the log grid, the
// Stats (F1) matrix shows THAT contact's entity instead of sitting blank.
// Only the matrix is redirected — every other tab still edits the live entry.
@@ -151,18 +155,9 @@ function Field({ label, span = 1, className, children }: { label: string; span?:
);
}
export function DetailsPanel({ callsign, prefix, operatorGrid, remoteGrid, qth, name, country, comment, note, details, onChange, wb, wbBusy, band, mode, bands, slotCall, slotBand, slotMode, slotWb, slotWbBusy, tab, onTab, keyerActive, onEditQso }: Props) {
export function DetailsPanel({ callsign, prefix, operatorGrid, remoteGrid, qth, name, country, comment, note, details, onChange, wb, wbBusy, band, mode, bands, satellites = [], slotCall, slotBand, slotMode, slotWb, slotWbBusy, tab, onTab, keyerActive, onEditQso }: Props) {
const { t } = useI18n();
const [internalOpen, setInternalOpen] = useState<TabName>('stats');
// The station's satellites, read once. Alphabetical because that is the only
// order a list of birds has, and an operator hunting AO-91 in a list sorted
// by when it was added is worse off than with a plain text box.
const [satellites, setSatellites] = useState<string[]>([]);
useEffect(() => {
GetListsSettings()
.then((l: any) => setSatellites([...((l?.satellites ?? []) as string[])].filter(Boolean).sort()))
.catch(() => {});
}, []);
const open = tab ?? internalOpen; // controlled when `tab` is provided
// Live award detection: run the SAME engine used at log time over the current
+19 -5
View File
@@ -1927,10 +1927,23 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
// operator's own log, and answering it must not modify that log.
const [rdaCmp, setRdaCmp] = useState<any>(null);
const [rdaCmpBusy, setRdaCmpBusy] = useState(false);
// Its own message, next to its own button.
//
// A failed comparison used to write into rdaMsg — which is rendered beside
// the FILL DISTRICTS button, a row above. The error appeared under a button
// nobody had pressed, and the one that had been pressed showed nothing at
// all, which reads as "the button does nothing".
const [rdaCmpMsg, setRdaCmpMsg] = useState<string>('');
const runRDACompare = async () => {
setRdaCmpBusy(true); setRdaCmp(null);
try { setRdaCmp(await CompareRDASources()); }
catch (e: any) { setRdaMsg(String(e?.message ?? e)); }
setRdaCmpBusy(true); setRdaCmp(null); setRdaCmpMsg('');
try {
const r: any = await CompareRDASources();
setRdaCmp(r);
// A comparison that finds nothing is a RESULT, and the most likely one on
// a tidy log. Without a word for it the panel looked like it had not run.
if (!r || (r.scanned ?? 0) === 0) setRdaCmpMsg(t('rda.cmpNoRussian'));
else if ((r.disagree ?? 0) === 0) setRdaCmpMsg(t('rda.cmpNoConflict'));
} catch (e: any) { setRdaCmpMsg(String(e?.message ?? e)); }
finally { setRdaCmpBusy(false); }
};
@@ -7421,7 +7434,7 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
<div className="flex items-center gap-3">
<Button size="sm" variant="secondary" onClick={runRDABackfill} disabled={rdaBusy}>
{rdaBusy ? <Loader2 className="size-3.5 animate-spin mr-1.5" /> : null}
{t('rda.backfillRun')}
{rdaBusy ? t('rda.backfillRunning') : t('rda.backfillRun')}
</Button>
{rdaMsg && <span className="text-xs text-muted-foreground">{rdaMsg}</span>}
</div>
@@ -7435,8 +7448,9 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
<div className="flex items-center gap-3">
<Button size="sm" variant="secondary" onClick={runRDACompare} disabled={rdaCmpBusy}>
{rdaCmpBusy ? <Loader2 className="size-3.5 animate-spin mr-1.5" /> : null}
{t('rda.cmpRun')}
{rdaCmpBusy ? t('rda.cmpRunning') : t('rda.cmpRun')}
</Button>
{!!rdaCmpMsg && <span className="text-xs text-muted-foreground">{rdaCmpMsg}</span>}
{rdaCmp && (
<span className="text-xs text-muted-foreground">
{t('rda.cmpDone', {
+2 -2
View File
@@ -150,7 +150,7 @@ const en: Dict = {
'sec.email': 'E-mail (SMTP)', 'sec.lookup': 'Callsign Lookup',
'sec.ftx': 'FTx decodes', 'ftx.hint': 'What OpsLog does on its own with the digital decode stream.', 'ftx.enable': 'Auto-call', 'ftx.enableHint': 'answer a decode without clicking it', 'ftx.callWhen': 'Call a station that is:', 'ftx.watch': 'Watch list', 'ftx.watchHint': 'One callsign per line, wildcards allowed (4S7*, */P). A watched station is answered ahead of the criteria above.', 'ftx.watchOnlyIf': 'but only if it is also:', 'ftx.cooldown': 'Ignore a callsign for', 'ftx.warn': 'This keys your transmitter without asking. It answers CQ only, never while you are already transmitting, one station at a time, and every call is written to the log file with its reason. Halt stops it.', 'ftx.c_dxcc': 'a new DXCC entity', 'ftx.c_bandmode': 'a new band AND a new mode for the entity', 'ftx.c_band': 'a new band for the entity', 'ftx.c_mode': 'a new mode for the entity', 'ftx.c_slot': 'a new slot (band+mode never worked together)', 'ftx.c_grid': 'a new grid square', 'ftx.c_county': 'a new US county', 'ftx.c_pota': 'a new POTA park', 'ftx.c_pfx': 'a new WPX prefix',
'sec.bands': 'Bands', 'sec.satellites': 'Satellites', 'sat.hint': 'The satellites this station works. They are offered as a dropdown on the satellite fields, in alphabetical order.', 'sat.listLabel': 'One satellite per line', 'sat.listHint': 'Written into SAT_NAME exactly as spelled here, so use the name LoTW and the awards expect — AO-91, not AO91. Leaving the list empty simply keeps the field a plain text box.', 'sec.modes': 'Modes & default RST', 'sec.cluster': 'DX Cluster',
'sec.udp': 'Connections', 'sec.database': 'Database', 'sec.autostart': 'Autostart', 'sec.backup': 'Database backup', 'sec.uscounties': 'US Counties', 'nav.maintenance': 'Maintenance', 'sec.databases': 'Databases', 'db.hint': 'The reference data OpsLog keeps on disk. One line each, with what it holds and when it was last refreshed.', 'db.update': 'Update', 'db.never': 'never downloaded', 'db.cty': 'Country file (cty.dat)', 'db.ctyDetail': '{n} entities · file dated {d}', 'db.clublog': 'Club Log country exceptions', 'db.clublogDetail': '{n} exceptions · {d}', 'db.lotwUsers': 'LoTW users', 'db.lotwDetail': '{n} callsigns · {d}', 'db.scp': 'Super Check Partial (MASTER.SCP)', 'db.scpDetail': '{n} callsigns · {d}', 'db.uls': 'US counties (FCC ULS)', 'db.ulsDetail': '{n} callsigns · {d}', 'db.rda': 'Russian districts (RDA)', 'db.rdaDetail': '{n} callsigns, with their dated activity periods', 'db.rdaNote': 'built in', 'db.refLists': 'Award reference lists', 'db.refListsHint': 'Only the awards with an online source appear here; the others are shipped or edited by hand.', 'db.refDetail': '{n} references · {d}', 'db.refUpdated': '{code}: {n} references.', 'db.noRefLists': 'No award has an online reference list.', 'sec.rda': 'Russian districts (RDA)', 'rda.hint': 'The offline district database, and the one bulk operation it feeds.', 'rda.dbTitle': 'District database', 'rda.dbCount': '{n} Russian callsigns, each with the district it operates from and, where it moved, the dated periods it operated from each one. Built into OpsLog — nothing to download.', 'rda.backfillTitle': 'Fill the district on existing QSOs', 'rda.backfillIntro': 'Goes through every contact with a Russian entity and assigns its RDA reference, using the district the station was in ON THE DAY of the contact.', 'rda.useCurrent': 'Also use the current district for stations with no recorded history', 'rda.useCurrentHint': '(true for the great majority — the database records a history precisely for the callsigns that moved — but it is an assumption, not a dated fact)', 'rda.backfillRun': 'Fill districts', 'rda.backfillDone': '{s} Russian QSOs — {d} from a dated record, {c} from the current district, {u} unknown, {k} already had one.', 'rda.cmpTitle': 'Compare the two district sources', 'rda.cmpRun': 'Compare', 'rda.cmpDone': '{s} Russian QSOs — {a} identical, {d} differ, {l} only in the log, {b} only in the database', 'rda.cmpCall': 'Callsign', 'rda.cmpDate': 'Date', 'rda.cmpFromLog': 'Log (CNTY)', 'rda.cmpFromDb': 'RDA database', 'rda.cmpListHint': 'Showing {n} of {d} — click a callsign to open the contact.', 'rda.cmpOpen': 'Open this QSO', 'rda.cmpKind': 'Database', 'rda.cmpDated': 'dated', 'rda.cmpCurrent': 'current', 'rda.neverOverwrites': 'A reference you assigned by hand is never overwritten.',
'sec.udp': 'Connections', 'sec.database': 'Database', 'sec.autostart': 'Autostart', 'sec.backup': 'Database backup', 'sec.uscounties': 'US Counties', 'nav.maintenance': 'Maintenance', 'sec.databases': 'Databases', 'db.hint': 'The reference data OpsLog keeps on disk. One line each, with what it holds and when it was last refreshed.', 'db.update': 'Update', 'db.never': 'never downloaded', 'db.cty': 'Country file (cty.dat)', 'db.ctyDetail': '{n} entities · file dated {d}', 'db.clublog': 'Club Log country exceptions', 'db.clublogDetail': '{n} exceptions · {d}', 'db.lotwUsers': 'LoTW users', 'db.lotwDetail': '{n} callsigns · {d}', 'db.scp': 'Super Check Partial (MASTER.SCP)', 'db.scpDetail': '{n} callsigns · {d}', 'db.uls': 'US counties (FCC ULS)', 'db.ulsDetail': '{n} callsigns · {d}', 'db.rda': 'Russian districts (RDA)', 'db.rdaDetail': '{n} callsigns, with their dated activity periods', 'db.rdaNote': 'built in', 'db.refLists': 'Award reference lists', 'db.refListsHint': 'Only the awards with an online source appear here; the others are shipped or edited by hand.', 'db.refDetail': '{n} references · {d}', 'db.refUpdated': '{code}: {n} references.', 'db.noRefLists': 'No award has an online reference list.', 'sec.rda': 'Russian districts (RDA)', 'rda.hint': 'The offline district database, and the one bulk operation it feeds.', 'rda.dbTitle': 'District database', 'rda.dbCount': '{n} Russian callsigns, each with the district it operates from and, where it moved, the dated periods it operated from each one. Built into OpsLog — nothing to download.', 'rda.backfillTitle': 'Fill the district on existing QSOs', 'rda.backfillIntro': 'Goes through every contact with a Russian entity and assigns its RDA reference, using the district the station was in ON THE DAY of the contact.', 'rda.useCurrent': 'Also use the current district for stations with no recorded history', 'rda.useCurrentHint': '(true for the great majority — the database records a history precisely for the callsigns that moved — but it is an assumption, not a dated fact)', 'rda.backfillRun': 'Fill districts', 'rda.backfillDone': '{s} Russian QSOs — {d} from a dated record, {c} from the current district, {u} unknown, {k} already had one.', 'rda.cmpTitle': 'Compare the two district sources', 'rda.cmpRunning': 'Comparing…', 'rda.cmpNoConflict': 'No disagreement — both sources say the same district everywhere.', 'rda.cmpNoRussian': 'No Russian contacts to compare.', 'rda.backfillRunning': 'Filling…', 'rda.cmpRun': 'Compare', 'rda.cmpDone': '{s} Russian QSOs — {a} identical, {d} differ, {l} only in the log, {b} only in the database', 'rda.cmpCall': 'Callsign', 'rda.cmpDate': 'Date', 'rda.cmpFromLog': 'Log (CNTY)', 'rda.cmpFromDb': 'RDA database', 'rda.cmpListHint': 'Showing {n} of {d} — click a callsign to open the contact.', 'rda.cmpOpen': 'Open this QSO', 'rda.cmpKind': 'Database', 'rda.cmpDated': 'dated', 'rda.cmpCurrent': 'current', 'rda.neverOverwrites': 'A reference you assigned by hand is never overwritten.',
'sec.webpublish': 'Web publishing', 'wpub.hint': 'Publishes your log as a file for a website: a standalone HTML page or a CSV, written locally and optionally uploaded by FTP. It is refreshed when you log a QSO and, if you set an interval, on a timer.', 'wpub.enable': 'Publish the log to a file', 'wpub.fileSection': 'The file', 'wpub.format': 'Format', 'wpub.formatHtml': 'HTML page', 'wpub.formatCsv': 'CSV', 'wpub.folder': 'Output folder', 'wpub.browse': 'Browse…', 'wpub.fileName': 'File name', 'wpub.title': 'Page title', 'wpub.titlePh': 'blank = your callsign', 'wpub.count': 'Last N QSOs', 'wpub.every': 'Refresh every', 'wpub.everyHint': 'minutes — 0 = only when a QSO is logged', 'wpub.columns': 'Columns', 'wpub.columnsCount': '{n} of {total} chosen', 'wpub.columnsPick': 'Choose columns…', 'wpub.columnsSearch': 'Search a field…', 'wpub.removeColumn': 'Click to remove', 'wpub.columnsHint': 'Click to add or remove. The order shown here is the order in the file.', 'wpub.ftpEnable': 'Upload by FTP', 'wpub.ftpHost': 'Server / port', 'wpub.ftpUser': 'User', 'wpub.ftpPassword': 'Password', 'wpub.ftpFolder': 'Remote folder', 'wpub.ftpFileName': 'Remote file name', 'wpub.ftpTls': 'Use TLS (FTPS)', 'wpub.publishNow': 'Publish now', 'wpub.testFtp': 'Test connection', 'wpub.lastRun': 'Last run:', 'sec.adifmon': 'ADIF monitor',
'sec.foldersync': 'Sync across PCs', 'sync.hint': 'Point every OpsLog at the SAME folder — one your PCs already synchronise (Seafile, OneDrive, Dropbox, a NAS share). Each machine writes what it logs there and reads the others; the databases themselves are never shared.', 'sync.enable': 'Keep my contacts in step across my PCs', 'sync.machine': 'This PC', 'sync.folder': 'Folder', 'sync.choose': 'Choose…', 'sync.state': 'State', 'sync.thisPc': 'This PC', 'sync.lastSync': 'Last check', 'sync.sent': 'Sent', 'sync.received': 'Received', 'sync.never': 'never', 'sync.noPeers': 'No other PC has written to this folder yet.', 'sync.behind': 'new contacts waiting', 'sync.now': 'Synchronise now', 'sync.applied': '{n} change(s) taken from the folder.', 'sync.saved': 'Saved.',
'adifmon.hint': 'Watch external ADIF files and import new QSOs automatically — e.g. fldigi logging RTTY, or N1MM/VarAC. Imported QSOs are enriched, de-duplicated and uploaded to your external services just like a QSO logged here.',
@@ -636,7 +636,7 @@ const fr: Dict = {
'sec.email': 'E-mail (SMTP)', 'sec.lookup': "Recherche d'indicatif",
'sec.ftx': 'Décodages FTx', 'ftx.hint': 'Ce quOpsLog fait de lui-même avec le flux de décodages numériques.', 'ftx.enable': 'Appel automatique', 'ftx.enableHint': 'répondre à un décodage sans cliquer', 'ftx.callWhen': 'Appeler une station qui est :', 'ftx.watch': 'Liste de surveillance', 'ftx.watchHint': 'Un indicatif par ligne, jokers acceptés (4S7*, */P). Une station surveillée est appelée avant les critères ci-dessus.', 'ftx.watchOnlyIf': 'mais seulement si elle est aussi :', 'ftx.cooldown': 'Ignorer un indicatif pendant', 'ftx.warn': 'Ceci met ton émetteur en marche sans te demander. Uniquement sur un CQ, jamais pendant que tu émets déjà, une station à la fois, et chaque appel est écrit dans le journal avec sa raison. Stop linterrompt.', 'ftx.c_dxcc': 'une nouvelle entité DXCC', 'ftx.c_bandmode': 'une nouvelle bande ET un nouveau mode pour lentité', 'ftx.c_band': 'une nouvelle bande pour lentité', 'ftx.c_mode': 'un nouveau mode pour lentité', 'ftx.c_slot': 'un nouveau slot (bande+mode jamais faits ensemble)', 'ftx.c_grid': 'un nouveau carré locator', 'ftx.c_county': 'un nouveau comté US', 'ftx.c_pota': 'un nouveau parc POTA', 'ftx.c_pfx': 'un nouveau préfixe WPX',
'sec.bands': 'Bandes', 'sec.satellites': 'Satellites', 'sat.hint': "Les satellites que cette station travaille. Ils sont proposés en liste déroulante sur les champs satellite, par ordre alphabétique.", 'sat.listLabel': 'Un satellite par ligne', 'sat.listHint': "Inscrit dans SAT_NAME exactement tel qu'écrit ici : utilise le nom attendu par LoTW et les diplômes — AO-91, pas AO91. Une liste vide laisse simplement le champ en saisie libre.", 'sec.modes': 'Modes & RST par défaut', 'sec.cluster': 'DX Cluster',
'sec.udp': 'Connexions', 'sec.database': 'Base de données', 'sec.autostart': 'Démarrage auto', 'sec.backup': 'Sauvegarde base', 'sec.uscounties': 'Comtés US', 'nav.maintenance': 'Maintenance', 'sec.databases': 'Bases de données', 'db.hint': 'Les données de référence quOpsLog garde sur disque. Une ligne chacune, avec ce quelle contient et sa dernière actualisation.', 'db.update': 'Mettre à jour', 'db.never': 'jamais téléchargée', 'db.cty': 'Fichier pays (cty.dat)', 'db.ctyDetail': '{n} entités · fichier daté du {d}', 'db.clublog': 'Exceptions pays Club Log', 'db.clublogDetail': '{n} exceptions · {d}', 'db.lotwUsers': 'Utilisateurs LoTW', 'db.lotwDetail': '{n} indicatifs · {d}', 'db.scp': 'Super Check Partial (MASTER.SCP)', 'db.scpDetail': '{n} indicatifs · {d}', 'db.uls': 'Comtés US (FCC ULS)', 'db.ulsDetail': '{n} indicatifs · {d}', 'db.rda': 'Districts russes (RDA)', 'db.rdaDetail': '{n} indicatifs, avec leurs périodes dactivité datées', 'db.rdaNote': 'intégrée', 'db.refLists': 'Listes de références des diplômes', 'db.refListsHint': 'Seuls les diplômes ayant une source en ligne apparaissent ici ; les autres sont livrés ou édités à la main.', 'db.refDetail': '{n} références · {d}', 'db.refUpdated': '{code} : {n} références.', 'db.noRefLists': 'Aucun diplôme na de liste de références en ligne.', 'sec.rda': 'Districts russes (RDA)', 'rda.hint': 'La base de districts hors ligne, et lunique opération de masse quelle alimente.', 'rda.dbTitle': 'Base des districts', 'rda.dbCount': '{n} indicatifs russes, chacun avec le district doù il émet et, pour ceux qui ont déménagé, les périodes datées passées dans chacun. Intégrée à OpsLog — rien à télécharger.', 'rda.backfillTitle': 'Renseigner le district sur les QSO existants', 'rda.backfillIntro': 'Parcourt tous les contacts avec une entité russe et attribue leur référence RDA, en utilisant le district où se trouvait la station LE JOUR du contact.', 'rda.useCurrent': 'Utiliser aussi le district actuel pour les stations sans historique connu', 'rda.useCurrentHint': '(vrai pour la grande majorité — la base enregistre un historique justement pour les indicatifs qui ont bougé — mais cest une supposition, pas un fait daté)', 'rda.backfillRun': 'Renseigner les districts', 'rda.backfillDone': '{s} QSO russes — {d} depuis une période datée, {c} depuis le district actuel, {u} inconnus, {k} en avaient déjà un.', 'rda.cmpTitle': 'Comparer les deux sources de district', 'rda.cmpRun': 'Comparer', 'rda.cmpDone': '{s} QSO russes — {a} identiques, {d} divergents, {l} seulement dans le log, {b} seulement dans la base', 'rda.cmpCall': 'Indicatif', 'rda.cmpDate': 'Date', 'rda.cmpFromLog': 'Log (CNTY)', 'rda.cmpFromDb': 'Base RDA', 'rda.cmpListHint': '{n} affichés sur {d} — cliquer un indicatif ouvre le contact.', 'rda.cmpOpen': 'Ouvrir ce QSO', 'rda.cmpKind': 'Base', 'rda.cmpDated': 'daté', 'rda.cmpCurrent': 'courant', 'rda.neverOverwrites': 'Une référence attribuée à la main nest jamais écrasée.',
'sec.udp': 'Connexions', 'sec.database': 'Base de données', 'sec.autostart': 'Démarrage auto', 'sec.backup': 'Sauvegarde base', 'sec.uscounties': 'Comtés US', 'nav.maintenance': 'Maintenance', 'sec.databases': 'Bases de données', 'db.hint': 'Les données de référence quOpsLog garde sur disque. Une ligne chacune, avec ce quelle contient et sa dernière actualisation.', 'db.update': 'Mettre à jour', 'db.never': 'jamais téléchargée', 'db.cty': 'Fichier pays (cty.dat)', 'db.ctyDetail': '{n} entités · fichier daté du {d}', 'db.clublog': 'Exceptions pays Club Log', 'db.clublogDetail': '{n} exceptions · {d}', 'db.lotwUsers': 'Utilisateurs LoTW', 'db.lotwDetail': '{n} indicatifs · {d}', 'db.scp': 'Super Check Partial (MASTER.SCP)', 'db.scpDetail': '{n} indicatifs · {d}', 'db.uls': 'Comtés US (FCC ULS)', 'db.ulsDetail': '{n} indicatifs · {d}', 'db.rda': 'Districts russes (RDA)', 'db.rdaDetail': '{n} indicatifs, avec leurs périodes dactivité datées', 'db.rdaNote': 'intégrée', 'db.refLists': 'Listes de références des diplômes', 'db.refListsHint': 'Seuls les diplômes ayant une source en ligne apparaissent ici ; les autres sont livrés ou édités à la main.', 'db.refDetail': '{n} références · {d}', 'db.refUpdated': '{code} : {n} références.', 'db.noRefLists': 'Aucun diplôme na de liste de références en ligne.', 'sec.rda': 'Districts russes (RDA)', 'rda.hint': 'La base de districts hors ligne, et lunique opération de masse quelle alimente.', 'rda.dbTitle': 'Base des districts', 'rda.dbCount': '{n} indicatifs russes, chacun avec le district doù il émet et, pour ceux qui ont déménagé, les périodes datées passées dans chacun. Intégrée à OpsLog — rien à télécharger.', 'rda.backfillTitle': 'Renseigner le district sur les QSO existants', 'rda.backfillIntro': 'Parcourt tous les contacts avec une entité russe et attribue leur référence RDA, en utilisant le district où se trouvait la station LE JOUR du contact.', 'rda.useCurrent': 'Utiliser aussi le district actuel pour les stations sans historique connu', 'rda.useCurrentHint': '(vrai pour la grande majorité — la base enregistre un historique justement pour les indicatifs qui ont bougé — mais cest une supposition, pas un fait daté)', 'rda.backfillRun': 'Renseigner les districts', 'rda.backfillDone': '{s} QSO russes — {d} depuis une période datée, {c} depuis le district actuel, {u} inconnus, {k} en avaient déjà un.', 'rda.cmpTitle': 'Comparer les deux sources de district', 'rda.cmpRunning': 'Comparaison…', 'rda.cmpNoConflict': 'Aucune divergence — les deux sources donnent partout le même district.', 'rda.cmpNoRussian': 'Aucun contact russe à comparer.', 'rda.backfillRunning': 'Remplissage…', 'rda.cmpRun': 'Comparer', 'rda.cmpDone': '{s} QSO russes — {a} identiques, {d} divergents, {l} seulement dans le log, {b} seulement dans la base', 'rda.cmpCall': 'Indicatif', 'rda.cmpDate': 'Date', 'rda.cmpFromLog': 'Log (CNTY)', 'rda.cmpFromDb': 'Base RDA', 'rda.cmpListHint': '{n} affichés sur {d} — cliquer un indicatif ouvre le contact.', 'rda.cmpOpen': 'Ouvrir ce QSO', 'rda.cmpKind': 'Base', 'rda.cmpDated': 'daté', 'rda.cmpCurrent': 'courant', 'rda.neverOverwrites': 'Une référence attribuée à la main nest jamais écrasée.',
'sec.webpublish': 'Publication web', 'wpub.hint': "Publie ton journal dans un fichier destiné à un site web : une page HTML autonome ou un CSV, écrit en local et envoyé par FTP si tu le souhaites. Il est rafraîchi à chaque QSO enregistré et, si tu règles un intervalle, périodiquement.", 'wpub.enable': 'Publier le journal dans un fichier', 'wpub.fileSection': 'Le fichier', 'wpub.format': 'Format', 'wpub.formatHtml': 'Page HTML', 'wpub.formatCsv': 'CSV', 'wpub.folder': 'Dossier de sortie', 'wpub.browse': 'Parcourir…', 'wpub.fileName': 'Nom du fichier', 'wpub.title': 'Titre de la page', 'wpub.titlePh': 'vide = ton indicatif', 'wpub.count': 'N derniers QSO', 'wpub.every': 'Rafraîchir toutes les', 'wpub.everyHint': 'minutes — 0 = seulement à chaque QSO', 'wpub.columns': 'Colonnes', 'wpub.columnsCount': '{n} sur {total} choisis', 'wpub.columnsPick': 'Choisir les colonnes…', 'wpub.columnsSearch': 'Chercher un champ…', 'wpub.removeColumn': 'Cliquer pour retirer', 'wpub.columnsHint': 'Clique pour ajouter ou retirer. L ordre affiché ici est celui du fichier.', 'wpub.ftpEnable': 'Envoyer par FTP', 'wpub.ftpHost': 'Serveur / port', 'wpub.ftpUser': 'Utilisateur', 'wpub.ftpPassword': 'Mot de passe', 'wpub.ftpFolder': 'Dossier distant', 'wpub.ftpFileName': 'Nom du fichier distant', 'wpub.ftpTls': 'Utiliser TLS (FTPS)', 'wpub.publishNow': 'Publier maintenant', 'wpub.testFtp': 'Tester la connexion', 'wpub.lastRun': 'Dernière exécution :', 'sec.adifmon': 'Moniteur ADIF',
'sec.foldersync': 'Synchro entre PC', 'sync.hint': 'Fais pointer chaque OpsLog vers le MÊME dossier — un dossier que tes PC synchronisent déjà (Seafile, OneDrive, Dropbox, un partage NAS). Chaque machine y écrit ce quelle enregistre et lit celui des autres ; les bases de données, elles, ne sont jamais partagées.', 'sync.enable': 'Garder mes contacts à jour sur tous mes PC', 'sync.machine': 'Ce PC', 'sync.folder': 'Dossier', 'sync.choose': 'Choisir…', 'sync.state': 'État', 'sync.thisPc': 'Ce PC', 'sync.lastSync': 'Dernière vérification', 'sync.sent': 'Envoyés', 'sync.received': 'Reçus', 'sync.never': 'jamais', 'sync.noPeers': 'Aucun autre PC na encore écrit dans ce dossier.', 'sync.behind': 'nouveaux contacts en attente', 'sync.now': 'Synchroniser maintenant', 'sync.applied': '{n} changement(s) repris du dossier.', 'sync.saved': 'Enregistré.',
'adifmon.hint': "Surveille des fichiers ADIF externes et importe les nouveaux QSO automatiquement — ex. fldigi en RTTY, ou N1MM/VarAC. Les QSO importés sont enrichis, dédoublonnés et envoyés à tes services externes comme un QSO loggé ici.",