diff --git a/frontend/editor/public/locales/en-US/translation.toml b/frontend/editor/public/locales/en-US/translation.toml index be90cb180a..eb2c80c981 100644 --- a/frontend/editor/public/locales/en-US/translation.toml +++ b/frontend/editor/public/locales/en-US/translation.toml @@ -4102,6 +4102,12 @@ deviceHint = "Removes the local copy. The cloud copy is kept." everywhere = "Everywhere" everywhereHint = "Deletes the file from this device and the cloud." +[filesPage.diskLink] +conflict = "Disk changed" +conflictHint = "The file on disk changed while you had unsaved edits. Your version is shown - saving will overwrite the one on disk." +orphaned = "Not on disk" +orphanedHint = "The original at {{path}} is gone. This copy is only here - saving it will ask for a new location." + [filesPage.empty] hint = "Drop PDFs anywhere on this page to upload, or use the New folder button to organize your files." newFolderCta = "Create folder" @@ -4189,12 +4195,6 @@ newFolderPlaceholder = "Folder name" newFolderToggle = "Create new folder…" title = "Move to folder" -[filesPage.diskLink] -conflict = "Disk changed" -conflictHint = "The file on disk changed while you had unsaved edits. Your version is shown - saving will overwrite the one on disk." -orphaned = "Not on disk" -orphanedHint = "The original at {{path}} is gone. This copy is only here - saving it will ask for a new location." - [filesPage.origin] all = "All sources" cloud = "Cloud" diff --git a/frontend/editor/src/core/services/diskFileSync.test.ts b/frontend/editor/src/core/services/diskFileSync.test.ts index 9bc0a829b7..8458c8b0d6 100644 --- a/frontend/editor/src/core/services/diskFileSync.test.ts +++ b/frontend/editor/src/core/services/diskFileSync.test.ts @@ -31,8 +31,11 @@ vi.mock("@app/services/fileStorage", () => ({ const downloadFileWithPolicy = vi.hoisted(() => vi.fn( - async (_request: Record) => - ({ savedPath: "C:/elsewhere/report.pdf" }) as any, + async ( + _request: Record, + ): Promise<{ savedPath?: string; cancelled?: boolean }> => ({ + savedPath: "C:/elsewhere/report.pdf", + }), ), ); vi.mock("@app/services/exportWithPolicy", () => ({ downloadFileWithPolicy })); diff --git a/frontend/editor/src/core/services/diskFileSync.ts b/frontend/editor/src/core/services/diskFileSync.ts index 28d192ce31..e8bb60bcd7 100644 --- a/frontend/editor/src/core/services/diskFileSync.ts +++ b/frontend/editor/src/core/services/diskFileSync.ts @@ -274,6 +274,19 @@ export async function saveOrphanAsCopy( } } +/** The bit of i18next this module needs, if it has been initialised at all. */ +interface Translator { + t: (key: string, options?: Record) => string; +} + +function isTranslator(value: unknown): value is Translator { + return ( + typeof value === "object" && + value !== null && + typeof (value as Translator).t === "function" + ); +} + /** * Best-effort translation without a hard dependency on i18n being initialised — * this module runs from storage/hydration paths that have no React context. The @@ -286,8 +299,8 @@ function translate( params?: Record, ): string { try { - const i18next = (globalThis as Record)?.i18next; - if (i18next && typeof i18next.t === "function") { + const i18next = (globalThis as Record).i18next; + if (isTranslator(i18next)) { return i18next.t(key, { defaultValue, ...params }); } } catch { diff --git a/frontend/editor/src/core/services/pruneMissingRecentFiles.test.ts b/frontend/editor/src/core/services/pruneMissingRecentFiles.test.ts index 416d7e7398..73cb372d5f 100644 --- a/frontend/editor/src/core/services/pruneMissingRecentFiles.test.ts +++ b/frontend/editor/src/core/services/pruneMissingRecentFiles.test.ts @@ -1,6 +1,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import type { StirlingFileStub } from "@app/types/fileContext"; import type { FileId } from "@app/types/file"; +import type { ToolId } from "@app/types/toolId"; const disk = vi.hoisted(() => ({ supported: true, @@ -94,7 +95,7 @@ describe("pruneMissingRecentFiles", () => { id: "edited" as FileId, localFilePath: "C:/docs/gone.pdf", versionNumber: 3, - toolHistory: [{ toolId: "split" as any, timestamp: 1 }], + toolHistory: [{ toolId: "split" as ToolId, timestamp: 1 }], }), ]; const result = await pruneMissingRecentFiles(stubs);