diff --git a/changelog.json b/changelog.json index bfd40ff..2fdb805 100644 --- a/changelog.json +++ b/changelog.json @@ -5,12 +5,12 @@ "en": [ "Cluster: \"Hide worked\" no longer hides a spot that is a new prefix, county, grid or park in an entity already worked.", "DX Cluster: a spot lifetime can be set — 5, 10, 15 minutes or your own value — after which spots leave the list and the band maps.", - "Call lookup: an option makes QRZ.com use the operator nickname as the name, falling back to the full name when none is published." + "Call lookup: QRZ.com now fills Name with the first name only, and optionally with the operator nickname instead." ], "fr": [ "Cluster : « Masquer les contactés » ne masque plus un spot qui est un nouveau préfixe, comté, carré ou parc dans une contrée déjà faite.", "Cluster DX : on peut fixer une durée de vie des spots — 5, 10, 15 minutes ou une valeur libre — au-delà de laquelle ils quittent la liste et les band maps.", - "Recherche d indicatif : une option fait utiliser à QRZ.com le surnom de l opérateur comme nom, avec repli sur le nom complet s il n y en a pas." + "Recherche d indicatif : QRZ.com remplit désormais Nom avec le seul prénom, et au choix avec le surnom de l opérateur." ] }, { diff --git a/internal/lookup/qrz.go b/internal/lookup/qrz.go index f70c834..74a823e 100644 --- a/internal/lookup/qrz.go +++ b/internal/lookup/qrz.go @@ -220,19 +220,6 @@ func composeQRZAddress(addr1, addr2, zip, country string) string { return strings.Join(parts, ", ") } -func joinName(first, last string) string { - first = strings.TrimSpace(first) - last = strings.TrimSpace(last) - switch { - case first != "" && last != "": - return first + " " + last - case first != "": - return first - default: - return last - } -} - func firstNonEmpty(s ...string) string { for _, v := range s { v = strings.TrimSpace(v) @@ -245,14 +232,25 @@ func firstNonEmpty(s ...string) string { // qrzName picks what goes in the log's Name field. // -// The nickname is only taken when the operator asked for it AND QRZ has one — -// a blank nickname must never blank the name, which is the whole reason this is -// a fallback rather than a swap. +// The FIRST name only. A log greets an operator, it does not address an +// envelope: "Robert" is what goes out on the air, and "Robert Smith" filled the +// field with something no one would ever send. The surname stays available in +// the record; it simply is not the name of the contact. +// +// The nickname is taken ahead of it when the operator asked for that AND QRZ +// has one — a blank nickname must never blank the name, which is the whole +// reason this is a fallback rather than a swap. +// +// The surname is the last resort: a record with no first name at all is better +// answered with a surname than with nothing. func qrzName(preferNickname bool, nickname, fname, name string) string { if preferNickname { if n := strings.TrimSpace(nickname); n != "" { return n } } - return joinName(fname, name) + if f := strings.TrimSpace(fname); f != "" { + return f + } + return strings.TrimSpace(name) } diff --git a/internal/lookup/qrzname_test.go b/internal/lookup/qrzname_test.go index f7f48a2..d8eeb87 100644 --- a/internal/lookup/qrzname_test.go +++ b/internal/lookup/qrzname_test.go @@ -2,30 +2,32 @@ package lookup import "testing" -// The nickname is the name an operator goes BY on the air, and that is what -// belongs in a log — "Bob", not "Robert J Smith". HamQTH's is already -// used that way; this brings QRZ into line for operators who ask for it. +// What goes in a log's Name field is the FIRST name. A log greets an operator; +// it does not address an envelope. "Robert Smith" filled the field with +// something no one would ever send on the air. // -// The one thing it must never do is blank the name. A published nickname is -// optional, so an empty one has to fall through to the registered name rather -// than win by being "preferred". -func TestQRZNamePrefersNicknameButFallsBack(t *testing.T) { +// The nickname wins ahead of it when asked for — but a published nickname is +// optional, so an empty one must fall through rather than blank the name. That +// is the whole difference between a fallback and a swap. +func TestQRZName(t *testing.T) { for _, tc := range []struct { + name string prefer bool - nickname, fname, name string + nickname, fname, last string want string }{ - {true, "Bob", "Robert", "Smith", "Bob"}, - {true, "", "Robert", "Smith", "Robert Smith"}, // no nickname published - {true, " ", "Robert", "Smith", "Robert Smith"}, // blank is not a nickname - {false, "Bob", "Robert", "Smith", "Robert Smith"}, // option off - {true, "Bob", "", "", "Bob"}, - {false, "", "Robert", "", "Robert"}, - {true, "", "", "Smith", "Smith"}, + {"first name only, never the surname", false, "Bob", "Robert", "Smith", "Robert"}, + {"nickname when asked for", true, "Bob", "Robert", "Smith", "Bob"}, + {"no nickname published falls back to the FIRST name", true, "", "Robert", "Smith", "Robert"}, + {"a blank nickname is not a nickname", true, " ", "Robert", "Smith", "Robert"}, + {"option off ignores the nickname", false, "Bob", "Robert", "Smith", "Robert"}, + {"surname is the last resort, not the default", true, "", "", "Smith", "Smith"}, + {"nothing published at all", false, "", "", "", ""}, + {"nickname alone", true, "Bob", "", "", "Bob"}, } { - if got := qrzName(tc.prefer, tc.nickname, tc.fname, tc.name); got != tc.want { - t.Errorf("qrzName(%v, %q, %q, %q) = %q, want %q", - tc.prefer, tc.nickname, tc.fname, tc.name, got, tc.want) + if got := qrzName(tc.prefer, tc.nickname, tc.fname, tc.last); got != tc.want { + t.Errorf("%s: qrzName(%v, %q, %q, %q) = %q, want %q", + tc.name, tc.prefer, tc.nickname, tc.fname, tc.last, got, tc.want) } } }