Say every Administration refusal in the reader's language

Stalwart explains a refused change in English, and several of its words
reached the page as they were: "Invalid domain name" for a reserved TLD,
"Invalid email address" for a catch-all, a grant refusal, and ihasmail's own
proxy messages. Every registry error type now has its own message, and a
value one of the registry's string validators refused is recognised by the
validator's wording and explained again. A domain clash or a missing domain
is worded for a domain rather than an account.

The one exception is kept on purpose: a password policy's reason follows a
translated sentence, because the rule is the server's and dropping it would
leave no way to find out why.

The mock now refuses a reserved TLD and a catch-all without a domain the way
the live server did. KNOWN-ISSUES records the fix, and that the last two live
cases -- an administrator-set password and the outranking guard -- held.

15 new strings in all nine catalogues, 3 retired; strings falling back to
English stay at 16.
This commit is contained in:
2026-09-13 17:18:15 -07:00
parent 822314e8b7
commit 15b1838e21
16 changed files with 270 additions and 50 deletions
+3 -3
View File
@@ -98,7 +98,7 @@ export function DomainSheet({ id, accountCount, onClose, onChanged, onCreated, o
void namesOf("DnsServer", [serverId]).then((n) => { if (!cancelled) setProvider(n.get(serverId) ?? null); }, () => {});
}
} catch (err) {
if (!cancelled) setLoadError(describeDirectoryError(err));
if (!cancelled) setLoadError(describeDirectoryError(err, "domain"));
}
})();
return () => {
@@ -148,7 +148,7 @@ export function DomainSheet({ id, accountCount, onClose, onChanged, onCreated, o
setRevision((n) => n + 1);
onChanged();
} catch (err) {
setError(describeDirectoryError(err));
setError(describeDirectoryError(err, "domain"));
} finally {
setBusy(false);
}
@@ -389,7 +389,7 @@ function RemoveDomain({ domain, accountCount, keys, canRemoveKeys, onDeleted }:
setError(
err instanceof DomainError && err.type === "objectIsLinked" && err.linked.length
? t("The server kept the domain: it is still used by {things}.", { things: describeLinked(err.linked) })
: describeDirectoryError(err),
: describeDirectoryError(err, "domain"),
);
} finally {
setBusy(false);
+1 -1
View File
@@ -47,7 +47,7 @@ export function DomainsAdmin({ selectedId }: { selectedId?: string }) {
} catch (err) {
if (!cancelled) {
setPage({ domains: [], total: 0 });
setError(describeDirectoryError(err));
setError(describeDirectoryError(err, "domain"));
}
}
})();