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 { Plus, Trash2 } from "lucide-react";
import { useSettings, type LabelVisibility } from "@/store/settings";
import { labelTree, descendantKeywords } from "@/lib/mailbox/labelTree";
@@ -8,6 +9,7 @@ import { promptDialog } from "@/ui/dialog";
import { t, tNode } from "@/lib/i18n";
export function LabelsSettings() {
const appName = useAppName();
const labels = useSettings((s) => s.settings.labels);
const update = useSettings((s) => s.update);
const [editing, setEditing] = useState<string | null>(null);
@@ -25,7 +27,7 @@ export function LabelsSettings() {
return (
<div>
<h1>{t("Labels")}</h1>
<p className="lead">{t("Labels are IMAP keywords stored on your messages, so every other client sees them. Names, colors and nesting are ihasmail\u2019s own and follow your account. Nesting is display only \u2014 it rewrites nothing in the mailbox.")}</p>
<p className="lead">{t("Labels are IMAP keywords stored on your messages, so every other client sees them. Names, colors and nesting are {app}\u2019s own and follow your account. Nesting is display only \u2014 it rewrites nothing in the mailbox.", { app: appName })}</p>
{labels.map((l) => (
<div key={l.keyword} className="card">
<div className="card-head">