Files
ihasmail/web/src/views/settings/AboutSettings.tsx
T
jcoffey 07b39eb9b6 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.
2026-09-19 14:27:34 -07:00

57 lines
3.7 KiB
TypeScript

import { useSession } from "@/store/session";
import { useAppName } from "@/lib/brand";
import { client } from "@/jmap/client";
import { DEFAULT_SOURCE_URL } from "@/lib/source";
import { APP_VERSION } from "@/lib/version";
import { withBase } from "@/lib/basePath";
import { t, tNode } from "@/lib/i18n";
export function AboutSettings() {
const appName = useAppName();
const session = useSession((s) => s.session);
const caps = Object.keys(session?.capabilities ?? {});
// A deployment running modified code should offer its own source, not ours.
const sourceUrl = session?.ihasmail?.sourceUrl ?? DEFAULT_SOURCE_URL;
return (
<div>
<h1>{t("About {app}", { app: appName })}</h1>
<p className="lead">{tNode("A fast, friendly, open-source webmail for {server}, built on JMAP.", { server: <a href="https://stalw.art" target="_blank" rel="noreferrer">{t("Stalwart Mail Server")}</a> })}</p>
<div className="row" style={{ gap: 16, alignItems: "center", marginBottom: 16 }}>
<img src={withBase("/img/logo.png")} alt={appName} width={96} />
<div>
{/* A product name and a version string: neither is a word to translate. */}
<div style={{ fontWeight: 700, fontSize: "1.2em" }} className="notranslate" translate="no">ihasmail v{APP_VERSION}</div>
<div className="hint">{tNode("AGPL-3.0-or-later · {source}", { source: <a href={sourceUrl} target="_blank" rel="noreferrer">{sourceUrl.replace(/^https?:\/\//, "")}</a> })}</div>
</div>
</div>
<h2>{t("Server")}</h2>
<table className="sessions-table">
<tbody>
<tr><td>{t("Signed in as")}</td><td>{session?.username}</td></tr>
<tr><td>{t("Stalwart")}</td><td>{describeServer(session?.ihasmail?.server)}</td></tr>
<tr><td>{t("Accounts")}</td><td>{Object.values(session?.accounts ?? {}).map((a) => a.name).join(", ")}</td></tr>
<tr><td>{t("Max upload")}</td><td>{t("{size} MB", { size: Math.round(client.maxSizeUpload / 1048576) })}</td></tr>
<tr><td>{t("Image privacy proxy")}</td><td>{session?.ihasmail?.imageProxy ? t("enabled") : t("disabled")}</td></tr>
</tbody>
</table>
<p className="hint" style={{ marginTop: 6 }}>{t("Stalwart does not publish its version number to mail clients, so {app} reports the edition where the server gives one. {app} requires 0.16 or newer, and sign-in refuses anything older.", { app: appName })}</p>
<p className="hint">{tNode("{app}'s own version is the date of the commit it was built from, followed by where that commit came from: {example} was built from a commit dated the 30th of August 2026 that arrived through pull request 129. A commit that did not come through one carries its short SHA instead — {sha}. The version deliberately says nothing about Stalwart; what this build needs from the server is the line above.", { example: <strong className="notranslate" translate="no">v2026.8.30+pr129</strong>, sha: <code>+g1fa6578</code> }, { app: appName })}</p>
<h2>{t("Server capabilities")}</h2>
<div className="row wrap gap-4">
{caps.map((c) => <span key={c} className="chip mono" style={{ fontSize: ".78em" }}>{c.replace("urn:ietf:params:jmap:", "")}</span>)}
</div>
</div>
);
}
/**
* Stalwart deliberately withholds its version from clients (it reports a fixed
* "1.0.0" wherever it publishes one at all), so the edition is all there is to
* show. The generation used to be reported here too, back when ihasmail spoke
* to both 0.15 and 0.16; it requires 0.16 now, so signing in at all is the
* answer to that question.
*/
function describeServer(server: { edition?: string | null } | undefined): string {
return server?.edition ? `0.16 or newer (${server.edition})` : "0.16 or newer";
}