Use American English spelling throughout

This commit is contained in:
2026-09-15 11:45:58 -07:00
parent 6ba89696ee
commit d1731efdb9
169 changed files with 786 additions and 795 deletions
+1 -1
View File
@@ -243,7 +243,7 @@ describe("updateEvent, per occurrence", () => {
});
describe("isThisAndFutureRefusal", () => {
it("recognises the refusal worth offering the series for", () => {
it("recognizes the refusal worth offering the series for", () => {
expect(isThisAndFutureRefusal(new CalendarSetError({
type: "invalidProperties",
description: "Occurrences of a this-and-future change cannot be modified individually.",
+1 -1
View File
@@ -264,7 +264,7 @@ describe("importing a file bigger than the server will take at once", () => {
* Re-importing the same file.
*
* The import kept the file's own UID from the day it was written, which is the
* whole of what is needed to recognise an event that is already here -- and
* whole of what is needed to recognize an event that is already here -- and
* nothing looked. Importing an export twice left second copies of everything,
* which the reporter's colleague hit during testing (#173, decided there:
* "duplicate checks on UIDs if UID present in event"). Issue #222 made that a
@@ -35,7 +35,7 @@ describe("applyLang", () => {
expect(document.documentElement.lang).toBe("en");
});
it("serves every language whose catalogue is shipped", () => {
it("serves every language whose catalog is shipped", () => {
for (const l of UI_LANGUAGES) {
applyLang({ ...DEFAULT_SETTINGS, uiLanguage: l.tag });
expect(document.documentElement.lang).toBe(l.tag);
+1 -1
View File
@@ -92,7 +92,7 @@ describe("importing an LDIF address book", () => {
const uids = Object.values(sets[0]!.create!).map((c) => c.uid as string);
expect(new Set(uids).size).toBe(2);
// Namespaced, so it is never mistaken for a UID a vCard author meant, and
// stable, so importing the same file again recognises these.
// stable, so importing the same file again recognizes these.
expect(uids.every((u) => u.startsWith("urn:x-ihasmail:ldif:"))).toBe(true);
});
@@ -95,7 +95,7 @@ describe("telling somebody what an LDIF re-import duplicated", () => {
expect(r.alike).toBe(0);
});
it("recognises a match on a second address", async () => {
it("recognizes a match on a second address", async () => {
server([card("c1", "Jane Doe", "[email protected]", "[email protected]")]);
const r = await useContacts.getState().importLdif(entry("Jane Doe", "[email protected]"), "book1");
expect(r.alike).toBe(1);
+2 -2
View File
@@ -19,13 +19,13 @@ describe("isRecurring", () => {
// and a base that is a different id. Neither makes it a series.
expect(isRecurring(ev({ id: "eaaaaai", baseEventId: "i" }))).toBe(false);
});
it("recognises a series by its rule, under either name", () => {
it("recognizes a series by its rule, under either name", () => {
expect(isRecurring(ev({ recurrenceRules: [{ "@type": "RecurrenceRule", frequency: "weekly" }] }))).toBe(true);
expect(isRecurring(ev({ excludedRecurrenceRules: [{ "@type": "RecurrenceRule", frequency: "monthly" }] }))).toBe(true);
// Stalwart 0.16 keeps a single rule under the singular name.
expect(isRecurring(ev({ recurrenceRule: { "@type": "RecurrenceRule", frequency: "weekly", count: 3 } }))).toBe(true);
});
it("recognises an occurrence, which arrives with no rule of its own", () => {
it("recognizes an occurrence, which arrives with no rule of its own", () => {
// A live 0.16.19 expands a weekly series into instances like this: an id
// per occurrence, a recurrenceId, and no rule attached.
expect(isRecurring(ev({ id: "iaaaaas", recurrenceId: "2030-03-11T10:00:00" }))).toBe(true);
@@ -73,7 +73,7 @@ describe("replying to a message somebody sent me", () => {
expect(addrs(d.cc)).toEqual([BOB.email]);
});
it("honours the sender's Reply-To, which is what it is for", async () => {
it("honors the sender's Reply-To, which is what it is for", async () => {
const d = await draftFor({ ...HERS, replyTo: [{ name: null, email: "[email protected]" }] } as Email, "reply");
expect(addrs(d.to)).toEqual(["[email protected]"]);
});
@@ -105,7 +105,7 @@ describe("replying to a message I sent", () => {
expect(addrs(d.cc)).toEqual([BOB.email]);
});
it("recognises my address however the identity stored it", async () => {
it("recognizes my address however the identity stored it", async () => {
// A hand-typed identity address can carry whitespace, and comparing
// strings rather than addresses made that enough to break the reply.
const padded = [{ id: "i1", name: "John", email: " [email protected] " }] as unknown as Identity[];
@@ -111,7 +111,7 @@ describe("reconcile", () => {
expect(useScheduled.getState().pending).toEqual({});
});
it("returns a message cancelled elsewhere to Drafts, as a draft again", async () => {
it("returns a message canceled elsewhere to Drafts, as a draft again", async () => {
const s = server(["e1"], [{ id: "s1", emailId: "e1", sendAt: FUTURE, undoStatus: "canceled" }]);
await useScheduled.getState().reconcile();
expect(moved(s.updates[0]!.e1!)).toEqual({ into: DRAFTS, outOf: SCHED });
@@ -156,7 +156,7 @@ describe("reconcile", () => {
});
it("keeps a message whose live hold was moved earlier than the one it replaced", async () => {
// Rescheduling to a sooner time leaves the cancelled submission holding the
// Rescheduling to a sooner time leaves the canceled submission holding the
// later sendAt. Going by timestamp alone would file a message back to
// Drafts while the queue still has it.
const s = server(
+9 -9
View File
@@ -333,11 +333,11 @@ function forImport(event: Partial<CalendarEvent>): Partial<CalendarEvent> {
}
/**
* The events a calendar already holds, for recognising a re-import.
* The events a calendar already holds, for recognizing a re-import.
*
* A UID is what makes an event the same event across calendars, and the import
* already keeps the file's own wherever there is one -- so the thing needed to
* recognise a re-import was there all along and nothing looked at it. Asked for
* recognize a re-import was there all along and nothing looked at it. Asked for
* once per import rather than once per event: `CalendarEvent/query` does take a
* `uid` filter, but a file of two thousand events would be two thousand
* queries.
@@ -618,7 +618,7 @@ export const useCalendar = create<CalendarState>((set, get) => ({
for (const b of birthdaysInRange(Object.values(useContacts.getState().cards), start, end)) {
birthdays.push({
key: b.id,
event: synthesiseBirthdayEvent(b),
event: synthesizeBirthdayEvent(b),
start: b.date,
end: new Date(b.date.getTime() + DAY_MS),
allDay: true,
@@ -639,7 +639,7 @@ export const useCalendar = create<CalendarState>((set, get) => ({
if (e.end <= start || e.start >= end) continue;
birthdays.push({
key: `${calId}:${e.uid}:${e.start.getTime()}`,
event: synthesiseSubscriptionEvent(sub.id, e),
event: synthesizeSubscriptionEvent(sub.id, e),
start: e.start,
end: e.end,
allDay: e.allDay,
@@ -821,7 +821,7 @@ export const useCalendar = create<CalendarState>((set, get) => ({
*
* The query deliberately omits `expandRecurrences`, so what comes back is the
* stored event and `id` is a real id. Callers rely on that — `InviteCard`
* removes a cancelled event by handing this straight to `destroyEvent` — so
* removes a canceled event by handing this straight to `destroyEvent` — so
* it is a property of this method, not an accident of the default.
*/
async findByUid(uid) {
@@ -881,7 +881,7 @@ export const useCalendar = create<CalendarState>((set, get) => ({
* the disagreement. Weighed on #279 and kept: an import is not the place to
* start sending mail on somebody's behalf, and the alternative is a file
* dropped into a calendar mailing a room full of people who never asked for
* it. Whoever is organising can send the update from the event itself.
* it. Whoever is organizing can send the update from the event itself.
*/
async importIcs(text, calendarId) {
const accountId = get().accountId!;
@@ -984,7 +984,7 @@ export const useCalendar = create<CalendarState>((set, get) => ({
* flattened the rule would import somewhere else as an unmaintainable pile.
*
* Written in the browser, unlike the import, which hands the parsing to the
* server. There is no `CalendarEvent/serialise` to hand this to -- the JMAP
* server. There is no `CalendarEvent/serialize` to hand this to -- the JMAP
* calendar drafts define parsing and nothing the other way -- so it is done
* here from the objects the server already returns.
*/
@@ -1053,7 +1053,7 @@ function birthdayCalendar(): Calendar {
}
/** A CalendarEvent shaped enough for the views, and for nothing else. */
function synthesiseBirthdayEvent(b: Birthday): CalendarEvent {
function synthesizeBirthdayEvent(b: Birthday): CalendarEvent {
const local = `${b.date.getFullYear()}-${String(b.date.getMonth() + 1).padStart(2, "0")}-${String(b.date.getDate()).padStart(2, "0")}T00:00:00`;
return {
id: b.id,
@@ -1088,7 +1088,7 @@ function subscriptionCalendar(sub: { id: string; name: string; color: string }):
} as unknown as Calendar;
}
function synthesiseSubscriptionEvent(subId: string, e: IcsEvent): CalendarEvent {
function synthesizeSubscriptionEvent(subId: string, e: IcsEvent): CalendarEvent {
const local = `${e.start.getFullYear()}-${String(e.start.getMonth() + 1).padStart(2, "0")}-${String(e.start.getDate()).padStart(2, "0")}T${String(e.start.getHours()).padStart(2, "0")}:${String(e.start.getMinutes()).padStart(2, "0")}:00`;
return {
id: `${subscriptionCalendarId(subId)}:${e.uid}`,
+1 -1
View File
@@ -623,7 +623,7 @@ export const useCompose = create<ComposeState>((set, get) => ({
});
}
};
// A scheduled send is already delayed, and cancelling it is a server-side
// A scheduled send is already delayed, and canceling it is a server-side
// operation from the Scheduled folder -- holding it locally first would
// only add a second, different kind of undo.
if (delay <= 0 || scheduling) {
+2 -2
View File
@@ -83,7 +83,7 @@ async function scanBook(accountId: Id, addressBookId: Id): Promise<{ byUid: Map<
* confusion rather than duplication, and being told costs nothing.
*
* One key per address, so a person whose second address matches is still
* recognised.
* recognized.
*/
function likenessKeys(c: Partial<ContactCard>): string[] {
const name = contactDisplayName(c as ContactCard).trim().toLowerCase();
@@ -225,7 +225,7 @@ interface ContactsState {
/**
* Import an address book in LDIF, read against Mozilla's schema.
*
* Mozilla's schema has no UID, so a re-import is recognised by the entry's
* Mozilla's schema has no UID, so a re-import is recognized by the entry's
* `dn` instead -- the same update-rather-than-duplicate rule the vCard import
* follows, on the only identity the file carries. `alike` is what is left
* over: entries that were created and still look like somebody already here,
+1 -1
View File
@@ -1331,7 +1331,7 @@ async function notifyNewMail(created: Id[], get: () => MailState) {
onClick: () => {
window.location.hash = "";
// The one navigation that does not go through wouter -- it is
// synthesising a popstate so the router picks the address up -- so
// synthesizing a popstate so the router picks the address up -- so
// it is also the one that has to add the mount prefix itself.
window.history.pushState({}, "", withBase(`/mail/${inbox}/${e.threadId}`));
window.dispatchEvent(new PopStateEvent("popstate"));
+2 -2
View File
@@ -177,7 +177,7 @@ export const useScheduled = create<ScheduledState>((set, get) => ({
* Nothing moves a message out of Scheduled when its hold expires -- the
* server sends it and updates the submission, but the message stays where we
* filed it. So on the way into the folder, settle up: what went out belongs
* in Sent, what was cancelled elsewhere belongs back in Drafts.
* in Sent, what was canceled elsewhere belongs back in Drafts.
*/
async reconcile() {
const mail = useMail.getState();
@@ -215,7 +215,7 @@ export const useScheduled = create<ScheduledState>((set, get) => ({
pending[emailId] = s;
continue;
}
// Cancelled goes back to Drafts; sent (or a submission the server no
// Canceled goes back to Drafts; sent (or a submission the server no
// longer knows about) goes to Sent, which is where it actually is.
const toDrafts = s?.undoStatus === "canceled";
const dest = toDrafts ? draftsId : sentId;
+1 -1
View File
@@ -26,7 +26,7 @@ interface SessionState {
logout(): Promise<void>;
refresh(): Promise<void>;
setAccount(id: Id): void;
/** The account to read and write for a capability, honouring the account switcher. */
/** The account to read and write for a capability, honoring the account switcher. */
accountFor(cap: string): Id | null;
/** The user's own account for a capability, whatever they are looking at. */
ownAccountFor(cap: string): Id | null;
+10 -10
View File
@@ -13,7 +13,7 @@ import { loadLanguage } from "@/lib/i18n";
/**
* "ihasmail" is a dark theme carrying the palette from ihasmail.org. It is a
* theme rather than an accent because it changes the backgrounds, borders and
* text as well as the highlight colour — an accent could not.
* text as well as the highlight color — an accent could not.
*/
export type Theme = "system" | "light" | "dark" | "ihasmail";
export type Density = "comfortable" | "cozy" | "compact";
@@ -83,7 +83,7 @@ export interface Settings {
* which is the half that stops an older device showing a theme nobody chose.
*/
theme: Theme;
/** The colours. */
/** The colors. */
palette: PaletteId;
/** Light, dark, or whatever the system says. */
mode: Mode;
@@ -131,7 +131,7 @@ export interface Settings {
/** Let messages follow the app's light/dark theme instead of always sitting on white. */
themeMessageBody: boolean;
/**
* Extend that to mail which brings colours of its own.
* Extend that to mail which brings colors of its own.
*
* Only meaningful with `themeMessageBody` on. Off by default because it
* cannot be done perfectly: see `markKeptSurfaces` in lib/html.ts for the
@@ -225,8 +225,8 @@ export interface Settings {
templates: Template[];
labels: Label[];
/**
* Folder colours, by mailbox id. Local to this browser, like every other
* colour here: JMAP has nowhere on a Mailbox to keep one.
* Folder colors, by mailbox id. Local to this browser, like every other
* color here: JMAP has nowhere on a Mailbox to keep one.
*/
folderColors: Record<string, string>;
sidebarCollapsed: boolean;
@@ -265,7 +265,7 @@ export interface Settings {
* sidebar with their own CSS keeps what they had until they choose otherwise.
*/
sidebarWidth: number | null;
/** Outlook-style colour categories for calendar events. */
/** Outlook-style color categories for calendar events. */
eventCategories: Array<{ name: string; color: string }>;
/** Default sending identity per account (JMAP has no such flag). */
defaultIdentityByAccount: Record<string, string>;
@@ -645,7 +645,7 @@ export function applyLang(s: Settings = useSettings.getState().settings): void {
const tag = resolveUiLanguage(s.uiLanguage);
document.documentElement.lang = tag;
/*
* The catalogue is fetched, so it lands a beat after the attribute. That
* The catalog is fetched, so it lands a beat after the attribute. That
* order is deliberate: `lang` is what stops Chrome offering to translate,
* and it should not wait on a network request to say something it already
* knows. English needs no fetch at all and resolves immediately.
@@ -663,7 +663,7 @@ export function applyTheme(s: Settings = useSettings.getState().settings): void
/*
* Two attributes, because they answer two questions. `data-theme` is the
* mode, and every dark-only rule in the stylesheet keys off it without
* knowing any palette exists; `data-palette` layers the colours on top. The
* knowing any palette exists; `data-palette` layers the colors on top. The
* accent variants out-specify both, which is what lets an accent still apply
* over any palette.
*/
@@ -678,7 +678,7 @@ export function applyTheme(s: Settings = useSettings.getState().settings): void
}
/**
* The browser chrome colour, read from the palette's own background so it does
* The browser chrome color, read from the palette's own background so it does
* not have to be listed twice and cannot drift from it.
*/
function paletteThemeColor(palette: PaletteId, mode: "light" | "dark"): string {
@@ -724,7 +724,7 @@ export function useEffectiveTheme(): "light" | "dark" {
export const settings = () => useSettings.getState().settings;
/**
* Primitive that changes whenever a date/time preference does, so memoised
* Primitive that changes whenever a date/time preference does, so memoized
* components that render dates re-render when the format is switched.
*/
export const dateTimeKey = (s: Settings): string => `${s.locale}|${s.dateFormat}|${s.timeFormat}`;
+1 -1
View File
@@ -108,7 +108,7 @@ export const useSieve = create<SieveState>((set, get) => ({
async saveRules(rules) {
const existing = get().scripts.find((s) => s.name === IHASMAIL_SCRIPT) ?? null;
// The last line of defence. Writing rules replaces the whole script, so
// The last line of defense. Writing rules replaces the whole script, so
// doing it from a baseline we never managed to read deletes whatever was
// there. Refusing is recoverable; overwriting is not.
if (existing) {