Call the app by its name in every sentence that names it (#406)

APP_NAME renames an instance, but only the sign-in page, the title bar and
a few headings used it. Two dozen sentences wrote "ihasmail" into
themselves, so a renamed instance still told people to keep an ihasmail
tab open and offered to open mail links "in ihasmail".

Those sentences now take the name as {app}, which also lets a translator
put it where their language wants it. brand.ts grew useAppName() for
components and currentAppName() for the few places that build strings
outside React.

Left as they are: the Files folder "ihasmail", the Sieve script
"ihasmail" and ihasmail.org. Those name things a person can go and look
at, and renaming them would rename real data.

All nine catalogues keep their translations: the name inside each one
became the placeholder. Three of the strings had no translation before
and still fall back to English.

A test walks the sources and the catalogues so a new sentence can't
hard-code the name again.
This commit is contained in:
jcoffey
2026-09-19 14:27:34 -07:00
committed by GitHub
parent 8a7ff5d42f
commit 9e3844e94a
25 changed files with 346 additions and 225 deletions
+3 -1
View File
@@ -1,4 +1,5 @@
import { useState } from "react";
import { useAppName } from "@/lib/brand";
import { useSettings, type ReadReceiptPolicy } from "@/store/settings";
import { useMail } from "@/store/mail";
import { domainOf } from "@/lib/address";
@@ -23,6 +24,7 @@ import { isEnforced } from "@/lib/settingsPolicy";
* behaves toward the reader and toward senders.
*/
export function PrivacySettings() {
const appName = useAppName();
const s = useSettings((st) => st.settings);
const update = useSettings((st) => st.update);
const trusted = s.trustedImageSenders;
@@ -43,7 +45,7 @@ export function PrivacySettings() {
<option value="always">{t("Always show")}</option>
</select>
<p className="hint">
{t("An image loaded from a sender's server tells them the message was opened, when, and from roughly where. Approved images are fetched by ihasmail's own server rather than the browser, so the sender learns none of those.")}
{t("An image loaded from a sender's server tells them the message was opened, when, and from roughly where. Approved images are fetched by {app}'s own server rather than the browser, so the sender learns none of those.", { app: appName })}
</p>
</div>
{trusted.length > 0 && (