From 1072ed65c1ffabf529ae763bde21c362c638f683 Mon Sep 17 00:00:00 2001 From: u8array Date: Wed, 7 Oct 2026 03:07:38 +0200 Subject: [PATCH] feat(printer): the stored object tabs show one list with each file's origin The listing walk reads the firmware drive Z: too, and nothing may delete there. --- README.md | 2 +- packages/core/src/lib/customFonts.ts | 4 +- packages/core/src/lib/hostDirectory.ts | 4 + packages/core/src/lib/storagePath.ts | 3 + .../core/src/lib/storedObjectOrigins.test.ts | 113 ++++++++++++ packages/core/src/lib/storedObjectOrigins.ts | 108 ++++++++++++ packages/core/src/registry/image.ts | 5 + .../PrinterObjectsSection.test.tsx | 121 ------------- .../PrinterSettings/PrinterObjectsSection.tsx | 134 -------------- .../PrinterSettings/PrinterStorage.test.tsx | 165 ++++++++++++++++++ .../PrinterSettings/PrinterStorage.tsx | 157 +++++++++++++++++ .../StoredFontsTab.printer.test.tsx | 73 ++++++++ .../PrinterSettings/StoredFontsTab.tsx | 153 ++++++++-------- .../StoredGraphicsTab.printer.test.tsx | 78 +++++++++ .../PrinterSettings/StoredGraphicsTab.tsx | 133 +++++++------- src/hooks/usePrinterListing.ts | 7 + src/lib/printerObjects.test.ts | 6 +- src/lib/printerObjects.ts | 5 +- src/locales/ar.ts | 19 +- src/locales/bg.ts | 19 +- src/locales/cs.ts | 19 +- src/locales/da.ts | 19 +- src/locales/de.ts | 19 +- src/locales/el.ts | 19 +- src/locales/en.ts | 19 +- src/locales/es.ts | 19 +- src/locales/et.ts | 19 +- src/locales/fa.ts | 19 +- src/locales/fi.ts | 19 +- src/locales/fr.ts | 19 +- src/locales/he.ts | 19 +- src/locales/hr.ts | 19 +- src/locales/hu.ts | 19 +- src/locales/it.ts | 19 +- src/locales/ja.ts | 19 +- src/locales/ko.ts | 19 +- src/locales/lt.ts | 19 +- src/locales/lv.ts | 19 +- src/locales/nl.ts | 19 +- src/locales/no.ts | 19 +- src/locales/pl.ts | 19 +- src/locales/pt.ts | 19 +- src/locales/ro.ts | 19 +- src/locales/sk.ts | 19 +- src/locales/sl.ts | 19 +- src/locales/sr.ts | 19 +- src/locales/sv.ts | 19 +- src/locales/tr.ts | 19 +- src/locales/zh-hans.ts | 19 +- src/locales/zh-hant.ts | 19 +- src/store/slices/printerObjectsSlice.ts | 4 +- 51 files changed, 1256 insertions(+), 627 deletions(-) create mode 100644 packages/core/src/lib/storedObjectOrigins.test.ts create mode 100644 packages/core/src/lib/storedObjectOrigins.ts delete mode 100644 src/components/PrinterSettings/PrinterObjectsSection.test.tsx delete mode 100644 src/components/PrinterSettings/PrinterObjectsSection.tsx create mode 100644 src/components/PrinterSettings/PrinterStorage.test.tsx create mode 100644 src/components/PrinterSettings/PrinterStorage.tsx create mode 100644 src/components/PrinterSettings/StoredFontsTab.printer.test.tsx create mode 100644 src/components/PrinterSettings/StoredGraphicsTab.printer.test.tsx create mode 100644 src/hooks/usePrinterListing.ts diff --git a/README.md b/README.md index c6714ff0..7cc29b9f 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,7 @@ On desktop, **Connect data** also reads an Excel worksheet. **File → Settings - The **Objects** group selects the fonts and graphics the **Setup Script** uploads. - It lists cached images and deletes the unused ones. -- On desktop it also reads what the printer holds. Show a stored graphic or let the printer draw a font sample. Delete objects on the printer. +- On desktop it reads what the printer holds, so every row says where its file stands. Show a stored graphic or let the printer draw a font sample. Delete objects on the printer. - Saved designs and label exports exclude **Setup Script** values such as printer name and locale. - **Clear** resets the **Setup Script** values and keeps the uploads. diff --git a/packages/core/src/lib/customFonts.ts b/packages/core/src/lib/customFonts.ts index 5f640e17..490b4be9 100644 --- a/packages/core/src/lib/customFonts.ts +++ b/packages/core/src/lib/customFonts.ts @@ -1,6 +1,6 @@ import type { CustomFontMapping, LabelConfig } from "../types/LabelConfig"; import { getFontBytes, holdsOtherBytes, isFontFile } from "./fontCache"; -import { DEFAULT_FONT_DEVICE, sanitizeStorageName, STORAGE_DEVICES, storageRefMatchesPath } from "./storagePath"; +import { DEFAULT_FONT_DEVICE, isWritableDevice, sanitizeStorageName, storageRefMatchesPath } from "./storagePath"; import { stripZplParamChars } from "./zplParams"; /** Strip-pattern; schema's regex `/^[A-Z0-9]$/` is the inverse. */ export const ALIAS_CHAR_RE = /[^A-Z0-9]/g; @@ -66,7 +66,7 @@ export const ZPL_BUILTIN_FONT_IDS = [ * ^A@ and ^CW can reference (spec p.63, p.168). .TTE stays, .OTF and the rest become .TTF (p.184). */ export function printerFontFileName(fileName: string): string | undefined { const first = fileName[0]?.toUpperCase() ?? ""; - const typedDevice = fileName[1] === ":" && (STORAGE_DEVICES as readonly string[]).includes(first) ? `${first}:` : undefined; + const typedDevice = fileName[1] === ":" && isWritableDevice(first) ? `${first}:` : undefined; const rest = typedDevice ? fileName.slice(2) : fileName; const device = typedDevice ?? `${DEFAULT_FONT_DEVICE}:`; const dot = rest.lastIndexOf("."); diff --git a/packages/core/src/lib/hostDirectory.ts b/packages/core/src/lib/hostDirectory.ts index 452fd39a..6d9f98f9 100644 --- a/packages/core/src/lib/hostDirectory.ts +++ b/packages/core/src/lib/hostDirectory.ts @@ -1,5 +1,6 @@ import { FONT_FORMAT_BY_EXT } from "./customFonts"; import { replyLines, unframed } from "./hostStatus"; +import { STORAGE_DEVICES } from "./storagePath"; export interface HostObject { device: string; @@ -16,6 +17,9 @@ export interface HostDirectory { export const hostObjectPath = (o: HostObject): string => `${o.device}:${o.name}.${o.ext}`; +/** ^HW also lists the firmware drive Z:, which no upload can name (spec p.240). */ +export const HOST_LISTING_DEVICES = [...STORAGE_DEVICES, "Z"] as const; + export type HostObjectKind = "graphic" | "font" | "format" | "other"; /** Extensions by what the object is, after the object lists of spec p.243 and p.182. */ diff --git a/packages/core/src/lib/storagePath.ts b/packages/core/src/lib/storagePath.ts index 2d492b84..11630428 100644 --- a/packages/core/src/lib/storagePath.ts +++ b/packages/core/src/lib/storagePath.ts @@ -10,6 +10,9 @@ export type StorageDevice = (typeof STORAGE_DEVICES)[number]; /** Where a locally picked font goes. */ export const DEFAULT_FONT_DEVICE = "E"; +export const isWritableDevice = (device: string): boolean => + (STORAGE_DEVICES as readonly string[]).includes(device.toUpperCase()); + /** DOS-style 8.3 (8-char uppercase alnum + underscore). */ export const MAX_STORAGE_NAME_LEN = 8; export const STORAGE_NAME_FILTER_RE = /[^A-Z0-9_]/g; diff --git a/packages/core/src/lib/storedObjectOrigins.test.ts b/packages/core/src/lib/storedObjectOrigins.test.ts new file mode 100644 index 00000000..eb9f327b --- /dev/null +++ b/packages/core/src/lib/storedObjectOrigins.test.ts @@ -0,0 +1,113 @@ +import { describe, it, expect } from "vitest"; +import { deleteKnowledge, hostListing, listingHolds, originState, storedObjectOrigins } from "./storedObjectOrigins"; +import type { HostDirectory } from "./hostDirectory"; + +const object = (device: string, name: string, ext: string, size = 100) => ({ device, name, ext, size }); +const dir = (device: string, objects: HostDirectory["objects"], bytesFree?: number): HostDirectory => ({ device, objects, bytesFree }); +const bytes = (paths: string[]) => paths.map((path) => ({ path, hasBytes: true })); + +describe("hostListing", () => { + it("folds one drive answering twice into one block and lists an aliased file once", () => { + const listing = hostListing([ + dir("R", [object("R", "LOGO", "GRF")], 100), + dir("R", [object("R", "LOGO", "GRF")], 100), + dir("A", [object("E", "ARIAL", "TTF")], 200), + dir("E", [object("E", "ARIAL", "TTF")], 200), + ]); + expect(listing.objects).toHaveLength(2); + }); + + it("reads neither absence nor free space off a drive whose block names another drive's files", () => { + const listing = hostListing([dir("A", [object("E", "ARIAL", "TTF")], 200), dir("E", [object("E", "ARIAL", "TTF")], 200)]); + expect(listing.devices).toEqual(["E"]); + expect(listing.free).toEqual([{ device: "E", bytesFree: 200 }]); + expect(storedObjectOrigins({ kind: "font", setupPaths: ["A:ARIAL.TTF"], local: [], listing }).map((r) => [r.key, r.host])).toEqual([ + ["A:ARIAL.TTF", "unknown"], + ["E:ARIAL.TTF", "present"], + ]); + }); + + it("still answers for a drive that holds nothing at all", () => { + const listing = hostListing([dir("R", [], 100)]); + expect(listing.devices).toEqual(["R"]); + expect(storedObjectOrigins({ kind: "graphic", setupPaths: ["R:A.GRF"], local: [], listing }).map((r) => r.host)).toEqual(["absent"]); + }); + + it("puts firmware objects behind the ones an upload could have written and names no room on their drive", () => { + const listing = hostListing([dir("Z", [object("Z", "TT0003M_", "FNT")], 0), dir("E", [object("E", "ARIAL", "TTF")], 200)]); + expect(listing.objects.map((o) => o.device)).toEqual(["E", "Z"]); + expect(listing.free).toEqual([{ device: "E", bytesFree: 200 }]); + }); +}); + +describe("listingHolds", () => { + it("answers for a path spelled another way than the listing spells it", () => { + const listing = hostListing([dir("E", [object("E", "ARIAL", "TTF")])]); + expect(listingHolds(listing, "e:arial.ttf")).toBe(true); + expect(listingHolds(listing, "R:ARIAL.TTF")).toBe(false); + }); +}); + +describe("storedObjectOrigins", () => { + it("folds the three sources into one row per file, local rows first", () => { + const listing = hostListing([dir("E", [object("E", "ARIAL", "TTF"), object("E", "CG_TIMES", "TTF")]), dir("R", [])]); + const rows = storedObjectOrigins({ kind: "font", setupPaths: ["E:ARIAL.TTF", "R:GONE.TTF"], local: bytes(["E:ARIAL.TTF", "E:LOCAL.TTF"]), listing }); + expect(rows.map((r) => [r.key, r.inSetup, r.hasCopy, r.host])).toEqual([ + ["E:ARIAL.TTF", true, true, "present"], + ["E:LOCAL.TTF", false, true, "absent"], + ["R:GONE.TTF", true, false, "absent"], + ["E:CG_TIMES.TTF", false, false, "present"], + ]); + }); + + it("keeps the spelling of the source that named the file and carries the listed object", () => { + const listing = hostListing([dir("E", [object("E", "ARIAL", "TTF", 4096)])]); + const [row] = storedObjectOrigins({ kind: "font", setupPaths: [], local: bytes(["e:arial.ttf"]), listing }); + expect(row?.path).toBe("e:arial.ttf"); + expect(row?.hostObject?.size).toBe(4096); + }); + + it("claims absence only for a drive that answered", () => { + const listing = hostListing([dir("R", [])]); + const rows = storedObjectOrigins({ kind: "graphic", setupPaths: ["R:A.GRF", "E:B.GRF"], local: [], listing }); + expect(rows.map((r) => r.host)).toEqual(["absent", "unknown"]); + expect(storedObjectOrigins({ kind: "graphic", setupPaths: ["R:A.GRF"], local: [], listing: undefined }).map((r) => r.host)).toEqual(["unknown"]); + }); + + it("takes only the listed objects of its own kind", () => { + const listing = hostListing([dir("R", [object("R", "LOGO", "GRF"), object("R", "LBL", "ZPL"), object("R", "SOME", "FNT")])]); + expect(storedObjectOrigins({ kind: "graphic", setupPaths: [], local: [], listing }).map((r) => r.key)).toEqual(["R:LOGO.GRF"]); + expect(storedObjectOrigins({ kind: "font", setupPaths: [], local: [], listing }).map((r) => r.key)).toEqual(["R:SOME.FNT"]); + }); +}); + +describe("originState", () => { + const row = (inSetup: boolean, hasCopy: boolean, host: "present" | "absent" | "unknown") => ({ key: "R:X.GRF", path: "R:X.GRF", inSetup, hasCopy, host }); + + it("says nothing about the printer before a listing", () => { + expect(originState(row(true, true, "unknown"))).toBe("unread"); + }); + + it("separates a setup entry that never arrived from a local file nothing provisions", () => { + expect(originState(row(true, true, "absent"))).toBe("missingOnPrinter"); + expect(originState(row(false, true, "absent"))).toBe("notOnPrinter"); + }); + + it("marks a listed file as the printer's own whenever nothing here can supply it", () => { + expect(originState(row(false, false, "present"))).toBe("printerOnly"); + expect(originState(row(true, false, "present"))).toBe("printerOnly"); + expect(originState(row(false, true, "present"))).toBe("onPrinter"); + expect(originState(row(true, true, "present"))).toBe("onPrinter"); + }); +}); + +describe("deleteKnowledge", () => { + const row = (inSetup: boolean, hasCopy: boolean) => ({ key: "R:X.GRF", path: "R:X.GRF", inSetup, hasCopy, host: "present" as const }); + + it("names the copy a delete leaves behind, and promises no re-upload without the file", () => { + expect(deleteKnowledge(row(true, true))).toBe("setupReuploads"); + expect(deleteKnowledge(row(true, false))).toBe("noCopy"); + expect(deleteKnowledge(row(false, true))).toBe("localCopy"); + expect(deleteKnowledge(row(false, false))).toBe("noCopy"); + }); +}); diff --git a/packages/core/src/lib/storedObjectOrigins.ts b/packages/core/src/lib/storedObjectOrigins.ts new file mode 100644 index 00000000..01c526db --- /dev/null +++ b/packages/core/src/lib/storedObjectOrigins.ts @@ -0,0 +1,108 @@ +import { hostObjectKind, hostObjectPath, type HostDirectory, type HostObject, type HostObjectKind } from "./hostDirectory"; +import { isWritableDevice, splitStorageKey, storageKey } from "./storagePath"; + +export type StoredObjectKind = Extract; + +export interface HostListing { + /** Only the drives that answered for themselves, so absence on them is real. */ + devices: string[]; + objects: HostObject[]; + free: { device: string; bytesFree: number }[]; +} + +export function hostListing(directories: readonly HostDirectory[]): HostListing { + // Two DIR blocks from one drive would name its free space twice. + const perDevice = new Map(); + for (const dir of directories) if (!perDevice.has(dir.device)) perDevice.set(dir.device, dir); + const blocks = [...perDevice.values()]; + return { + // A block listing another drive's objects is an alias: it answers for the target, not for itself. + devices: blocks.filter(namesItsOwn).map((d) => d.device), + objects: [...new Map(blocks.flatMap((d) => d.objects).map((o) => [storageKey(hostObjectPath(o)), o])).values()].sort(firmwareLast), + // Room is only worth naming where an upload may write. + free: blocks.flatMap((d) => + d.bytesFree === undefined || !isWritableDevice(d.device) || !namesItsOwn(d) ? [] : [{ device: d.device, bytesFree: d.bytesFree }], + ), + }; +} + +const namesItsOwn = (d: HostDirectory): boolean => d.objects.every((o) => o.device === d.device); + +function firmwareLast(a: HostObject, b: HostObject): number { + return Number(!isWritableDevice(a.device)) - Number(!isWritableDevice(b.device)); +} + +export const listingHolds = (listing: HostListing, path: string): boolean => + listing.objects.some((o) => storageKey(hostObjectPath(o)) === storageKey(path)); + +export type HostPresence = "present" | "absent" | "unknown"; + +export interface StoredObjectOrigin { + /** Keyed per drive: one name on two drives is two files. */ + key: string; + /** The owner's own spelling, not the normalised key. */ + path: string; + inSetup: boolean; + /** The bytes exist off the printer too. */ + hasCopy: boolean; + host: HostPresence; + hostObject?: HostObject; +} + +/** A file the app names. The bytes may be gone, as with a recall whose cache was cleared. */ +export interface LocalObject { + path: string; + hasBytes: boolean; +} + +export interface StoredObjectSources { + kind: StoredObjectKind; + setupPaths: readonly string[]; + local: readonly LocalObject[]; + listing: HostListing | undefined; +} + +/** Rows run local, then setup-only, then printer-only. */ +export function storedObjectOrigins({ kind, setupPaths, local, listing }: StoredObjectSources): StoredObjectOrigin[] { + const rows = new Map(); + const row = (path: string): StoredObjectOrigin => { + const key = storageKey(path); + const found = rows.get(key); + if (found) return found; + const fresh: StoredObjectOrigin = { key, path, inSetup: false, hasCopy: false, host: "unknown" }; + rows.set(key, fresh); + return fresh; + }; + for (const object of local) row(object.path).hasCopy ||= object.hasBytes; + // Bytes are the caller's claim, so a setup entry sets no `hasCopy`. + for (const path of setupPaths) row(path).inSetup = true; + for (const object of listing?.objects ?? []) { + if (hostObjectKind(object.ext) !== kind) continue; + const found = row(hostObjectPath(object)); + found.host = "present"; + found.hostObject = object; + } + if (listing) { + for (const found of rows.values()) { + if (found.host === "unknown" && listing.devices.includes(splitStorageKey(found.key).device)) found.host = "absent"; + } + } + return [...rows.values()]; +} + +/** `unread` means the drive never answered, so no row may claim anything. */ +export type OriginState = "unread" | "missingOnPrinter" | "notOnPrinter" | "onPrinter" | "printerOnly"; + +export function originState(o: StoredObjectOrigin): OriginState { + if (o.host === "unknown") return "unread"; + if (o.host === "absent") return o.inSetup ? "missingOnPrinter" : "notOnPrinter"; + return o.hasCopy ? "onPrinter" : "printerOnly"; +} + +export type DeleteKnowledge = "setupReuploads" | "localCopy" | "noCopy"; + +export function deleteKnowledge(o: StoredObjectOrigin): DeleteKnowledge { + // A setup entry without its file restores nothing, so it counts as no copy. + if (!o.hasCopy) return "noCopy"; + return o.inSetup ? "setupReuploads" : "localCopy"; +} diff --git a/packages/core/src/registry/image.ts b/packages/core/src/registry/image.ts index 8c4dea22..18811327 100644 --- a/packages/core/src/registry/image.ts +++ b/packages/core/src/registry/image.ts @@ -363,6 +363,11 @@ export function setupGraphicState( return entry.gfa === cached ? 'current' : 'stale'; } +/** A verbatim ^GF in the document is a copy like any other. */ +export function hasLocalGraphicBytes(p: ImageProps): boolean { + return getImage(p.imageId) !== undefined || p._gfaCache !== undefined || p.rawGf !== undefined; +} + /** Whether an encode is worth attempting. The encode itself may still refuse its result. */ export function canSendSetupGraphic(p: ImageProps): boolean { if (uploadKey(p) === undefined || cacheTooLarge(p)) return false; diff --git a/src/components/PrinterSettings/PrinterObjectsSection.test.tsx b/src/components/PrinterSettings/PrinterObjectsSection.test.tsx deleted file mode 100644 index b6db2221..00000000 --- a/src/components/PrinterSettings/PrinterObjectsSection.test.tsx +++ /dev/null @@ -1,121 +0,0 @@ -// @vitest-environment jsdom -import { describe, it, expect, afterEach, beforeEach, vi } from "vitest"; -import { render, cleanup, fireEvent, act } from "@testing-library/react"; -import { PrinterObjectsSection } from "./PrinterObjectsSection"; -import { useLabelStore } from "../../store/labelStore"; -import { DEFAULT_PRINT_TARGET } from "../../lib/printTarget"; -import { fallbackTranslations as en } from "../../locales"; -import type * as PrinterObjects from "../../lib/printerObjects"; - -const readPrinterObjects = vi.fn(); -const readPrinterObjectImage = vi.fn(); -const deletePrinterObject = vi.fn(); -vi.mock("../../lib/printerObjects", async (importOriginal) => ({ - ...(await importOriginal()), - readPrinterObjects: (...args: unknown[]) => readPrinterObjects(...args), - readPrinterObjectImage: (...args: unknown[]) => readPrinterObjectImage(...args), - deletePrinterObject: (...args: unknown[]) => deletePrinterObject(...args), -})); - -const loc = en.printerSettings.objects; -const pre = { device: "R", name: "PRE", ext: "GRF", size: 49924 }; -const png = { device: "E", name: "CHK06", ext: "PNG", size: 2203 }; -const font = { device: "E", name: "CG_TIMES", ext: "TTF", size: 62252 }; -const listing = [ - { device: "R", objects: [pre, { device: "R", name: "LBL", ext: "ZPL", size: 214 }], bytesFree: 7467008 }, - { device: "E", objects: [png, font], bytesFree: 47972352 }, -]; -const target = { kind: "network", host: "172.17.17.175", port: 9100 }; -const media = expect.objectContaining({ dpmm: expect.any(Number) }); -const listed = () => act(() => useLabelStore.setState({ printerObjects: { phase: "done", key: "net:172.17.17.175:9100", at: 0, directories: listing } })); - -afterEach(cleanup); -beforeEach(() => { - readPrinterObjects.mockReset(); - readPrinterObjectImage.mockReset(); - deletePrinterObject.mockReset(); - act(() => - useLabelStore.setState({ - printerObjects: { phase: "idle" }, - printerReading: undefined, - printTarget: { ...DEFAULT_PRINT_TARGET, host: "172.17.17.175" }, - printerProfile: { ...useLabelStore.getState().printerProfile, setupGraphics: [], setupFonts: [] }, - }), - ); -}); - -describe("PrinterObjectsSection", () => { - it("reads the printer on request and lists only the objects of its kind with the free space", async () => { - readPrinterObjects.mockResolvedValue({ kind: "ok", value: listing }); - const r = render(); - expect(r.getByText(loc.printerNotRead)).toBeTruthy(); - await act(async () => { - fireEvent.click(r.getByText(loc.readPrinter)); - }); - expect(r.getByText("R:PRE.GRF")).toBeTruthy(); - expect(r.getByText("E:CHK06.PNG")).toBeTruthy(); - expect(r.queryByText("R:LBL.ZPL")).toBeNull(); - expect(r.queryByText("E:CG_TIMES.TTF")).toBeNull(); - expect(r.getByText("R: 7292 KB free, E: 46848 KB free")).toBeTruthy(); - expect((r.getAllByText(loc.showObject) as HTMLButtonElement[]).map((b) => b.disabled)).toEqual([false, false]); - r.unmount(); - const fonts = render(); - expect(fonts.getByText("E:CG_TIMES.TTF")).toBeTruthy(); - expect(fonts.queryByText("R:PRE.GRF")).toBeNull(); - }); - - it("shows a stored graphic in a dialog and names one it cannot draw", async () => { - listed(); - readPrinterObjectImage.mockResolvedValueOnce({ kind: "ok", value: "data:image/png;base64,x" }); - const r = render(); - await act(async () => { - fireEvent.click(r.getAllByText(loc.showObject)[0] as HTMLElement); - }); - expect(readPrinterObjectImage).toHaveBeenCalledWith(target, pre, media); - expect((r.getByRole("img") as HTMLImageElement).alt).toBe("R:PRE.GRF"); - fireEvent.click(r.getByLabelText(en.app.close)); - readPrinterObjectImage.mockResolvedValueOnce({ kind: "ok", value: null }); - await act(async () => { - fireEvent.click(r.getAllByText(loc.showObject)[0] as HTMLElement); - }); - expect(r.getByRole("alert").textContent).toBe(loc.graphicUnreadable); - }); - - it("lets the printer draw a font sample and says when it drew nothing", async () => { - listed(); - readPrinterObjectImage.mockResolvedValueOnce({ kind: "ok", value: "data:image/png;base64,x" }); - const r = render(); - await act(async () => { - fireEvent.click(r.getByText(loc.showObject)); - }); - expect(readPrinterObjectImage).toHaveBeenCalledWith(target, font, media); - expect((r.getByRole("img") as HTMLImageElement).alt).toBe("E:CG_TIMES.TTF"); - fireEvent.click(r.getByLabelText(en.app.close)); - readPrinterObjectImage.mockResolvedValueOnce({ kind: "ok", value: null }); - await act(async () => { - fireEvent.click(r.getByText(loc.showObject)); - }); - expect(r.getByRole("alert").textContent).toBe(loc.fontSampleBlank); - }); - - it("asks per kind before deleting, warns when the setup script would upload it again, and reports a failed delete", async () => { - listed(); - act(() => useLabelStore.setState({ printerProfile: { ...useLabelStore.getState().printerProfile, setupFonts: [{ path: "E:CG_TIMES.TTF" }] } })); - deletePrinterObject.mockResolvedValue({ kind: "unreachable" }); - const r = render(); - fireEvent.click(r.getByText(loc.deleteObject)); - expect(r.getByText(`Delete E:CG_TIMES.TTF from the printer? Labels that use it fall back to another font. ${loc.setupReuploadHint}`)).toBeTruthy(); - fireEvent.click(r.getByText(en.app.cancel)); - expect(deletePrinterObject).not.toHaveBeenCalled(); - fireEvent.click(r.getByText(loc.deleteObject)); - await act(async () => { - fireEvent.click(r.getAllByText(loc.deleteObject).at(-1) as HTMLElement); - }); - expect(deletePrinterObject).toHaveBeenCalledWith(target, font); - expect(r.getByRole("alert").textContent).toMatch(/Could not reach the printer/); - r.unmount(); - const graphics = render(); - fireEvent.click(graphics.getAllByText(loc.deleteObject)[0] as HTMLElement); - expect(graphics.getByText("Delete R:PRE.GRF from the printer? Labels that recall it print without it.")).toBeTruthy(); - }); -}); diff --git a/src/components/PrinterSettings/PrinterObjectsSection.tsx b/src/components/PrinterSettings/PrinterObjectsSection.tsx deleted file mode 100644 index e3f42a8b..00000000 --- a/src/components/PrinterSettings/PrinterObjectsSection.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import { useState } from "react"; -import { InformationCircleIcon } from "@heroicons/react/16/solid"; -import { hostObjectKind, hostObjectPath, type HostObject, type HostObjectKind } from "@zplab/core/lib/hostDirectory"; -import { findSetupEntry } from "@zplab/core/lib/setupEntries"; -import { useT } from "../../hooks/useT"; -import { formatTemplate } from "../../lib/formatTemplate"; -import type { PrinterOutcome } from "../../lib/printerQuery"; -import { failureText, readingText } from "../../lib/printerStatusText"; -import { selectPrinterObjects, useLabelStore } from "../../store/labelStore"; -import { ConfirmDialog } from "../ui/ConfirmDialog"; -import { Tooltip } from "../ui/Tooltip"; -import { buttonCls, disabledCls, sectionHeadingCls, zplCommandTagCls } from "../ui/formStyles"; -import { PrinterImageDialog } from "./PrinterImageDialog"; - -type Kind = Extract; - -const kb = (bytes: number): string => String(bytes === 0 ? 0 : Math.max(1, Math.round(bytes / 1024))); - -/** The printer's own listing beside the setup script, read on request. */ -export function PrinterObjectsSection({ kind }: { kind: Kind }) { - const t = useT(); - const loc = t.printerSettings.objects; - const status = t.printerSettings.printerStatus; - const state = useLabelStore(selectPrinterObjects); - const step = useLabelStore((s) => s.printerReading); - const setupEntries = useLabelStore((s) => (kind === "graphic" ? s.printerProfile.setupGraphics : s.printerProfile.setupFonts)); - const read = useLabelStore((s) => s.readPrinterObjects); - const readImage = useLabelStore((s) => s.readPrinterObjectImage); - const remove = useLabelStore((s) => s.deletePrinterObject); - const [pendingDelete, setPendingDelete] = useState(null); - const [issue, setIssue] = useState(null); - const [graphic, setGraphic] = useState<{ path: string; read: PrinterOutcome | "reading" } | undefined>(); - - const reading = step !== undefined; - // A drive answering with two DIR blocks would list its objects and its free space twice. - const drives = state.phase === "done" ? [...new Map(state.directories.map((d) => [d.device, d])).values()] : []; - const objects = [...new Map(drives.flatMap((d) => d.objects).map((o) => [hostObjectPath(o), o])).values()].filter((o) => hostObjectKind(o.ext) === kind); - const free = drives.flatMap((d) => (d.bytesFree === undefined ? [] : [formatTemplate(loc.printerFreeFmt, { device: d.device, kb: kb(d.bytesFree) })])); - const line = - step !== undefined - ? readingText(status, step) - : state.phase === "failed" - ? failureText(status, state.failure) - : state.phase === "done" - ? formatTemplate(status.checkedAtFmt, { time: new Date(state.at).toLocaleTimeString() }) - : loc.printerNotRead; - const show = (object: HostObject) => { - const path = hostObjectPath(object); - setGraphic({ path, read: "reading" }); - void readImage(object).then((read) => setGraphic((current) => (current?.path === path ? { path, read } : current))); - }; - const confirmDelete = (object: HostObject) => { - setPendingDelete(null); - void remove(object).then((failure) => setIssue(failure ? failureText(status, failure) : null)); - }; - const readListing = () => { - setIssue(null); - void read(); - }; - const deleteMessage = (object: HostObject) => { - const path = hostObjectPath(object); - const question = formatTemplate(kind === "graphic" ? loc.deleteGraphicConfirmFmt : loc.deleteFontConfirmFmt, { path }); - return findSetupEntry(setupEntries, path) ? `${question} ${loc.setupReuploadHint}` : question; - }; - - return ( -
-
-
-

{loc.printerHeading}

- - - -
- ^HW -
-
- - - {line} - -
- {issue && ( -

- {issue} -

- )} - {state.phase === "done" && - (objects.length === 0 ? ( -

{loc.printerEmpty}

- ) : ( -
    - {objects.map((o) => { - const path = hostObjectPath(o); - return ( -
  • - - - {path} - - {formatTemplate(loc.objectSizeFmt, { kb: kb(o.size) })} - - - - - -
  • - ); - })} -
- ))} - {free.length > 0 &&

{free.join(", ")}

} - {state.phase === "done" && pendingDelete && ( - confirmDelete(pendingDelete)} - onCancel={() => setPendingDelete(null)} - /> - )} - {state.phase === "done" && graphic && ( - setGraphic(undefined)} /> - )} -
- ); -} diff --git a/src/components/PrinterSettings/PrinterStorage.test.tsx b/src/components/PrinterSettings/PrinterStorage.test.tsx new file mode 100644 index 00000000..81a9cbb8 --- /dev/null +++ b/src/components/PrinterSettings/PrinterStorage.test.tsx @@ -0,0 +1,165 @@ +// @vitest-environment jsdom +import { describe, it, expect, afterEach, beforeEach, vi } from "vitest"; +import { render, cleanup, fireEvent, act } from "@testing-library/react"; +import { PrinterObjectActions, PrinterStorageBar } from "./PrinterStorage"; +import { useLabelStore } from "../../store/labelStore"; +import { DEFAULT_PRINT_TARGET } from "../../lib/printTarget"; +import { fallbackTranslations as en } from "../../locales"; +import type { HostObject } from "@zplab/core/lib/hostDirectory"; +import type { StoredObjectOrigin } from "@zplab/core/lib/storedObjectOrigins"; +import type * as PrinterObjects from "../../lib/printerObjects"; + +const readPrinterObjects = vi.fn(); +const readPrinterObjectImage = vi.fn(); +const deletePrinterObject = vi.fn(); +vi.mock("../../lib/printerObjects", async (importOriginal) => ({ + ...(await importOriginal()), + readPrinterObjects: (...args: unknown[]) => readPrinterObjects(...args), + readPrinterObjectImage: (...args: unknown[]) => readPrinterObjectImage(...args), + deletePrinterObject: (...args: unknown[]) => deletePrinterObject(...args), +})); + +const loc = en.printerSettings.objects; +const pre = { device: "R", name: "PRE", ext: "GRF", size: 49924 }; +const font = { device: "E", name: "CG_TIMES", ext: "TTF", size: 62252 }; +const firmware = { device: "Z", name: "TT0003M_", ext: "FNT", size: 11000 }; +const listing = [ + { device: "R", objects: [pre], bytesFree: 7467008 }, + { device: "E", objects: [font], bytesFree: 47972352 }, +]; +const target = { kind: "network", host: "172.17.17.175", port: 9100 }; +const media = expect.objectContaining({ dpmm: expect.any(Number) }); +const origin = (hostObject: HostObject, extra: Partial = {}): StoredObjectOrigin & { hostObject: HostObject } => ({ + key: `${hostObject.device}:${hostObject.name}.${hostObject.ext}`, + path: `${hostObject.device}:${hostObject.name}.${hostObject.ext}`, + inSetup: false, + hasCopy: false, + host: "present", + hostObject, + ...extra, +}); + +afterEach(cleanup); +beforeEach(() => { + readPrinterObjects.mockReset(); + readPrinterObjectImage.mockReset(); + deletePrinterObject.mockReset(); + act(() => + useLabelStore.setState({ + printerObjects: { phase: "idle" }, + printerReading: undefined, + printTarget: { ...DEFAULT_PRINT_TARGET, host: "172.17.17.175" }, + }), + ); +}); + +describe("PrinterStorageBar", () => { + it("reads the printer on request and reports the free space of every drive that answered", async () => { + readPrinterObjects.mockResolvedValue({ kind: "ok", value: listing }); + const r = render(); + expect(r.getByText(loc.printerNotRead)).toBeTruthy(); + await act(async () => { + fireEvent.click(r.getByText(loc.readPrinter)); + }); + expect(r.getByText("R: 7292 KB free, E: 46848 KB free")).toBeTruthy(); + }); + + it("names a failed read instead of an empty listing", async () => { + readPrinterObjects.mockResolvedValue({ kind: "unreachable" }); + const r = render(); + await act(async () => { + fireEvent.click(r.getByText(loc.readPrinter)); + }); + expect(r.getByText(en.printerSettings.printerStatus.failUnreachable)).toBeTruthy(); + }); +}); + +describe("PrinterObjectActions", () => { + it("shows a stored graphic in a dialog and names one it cannot draw", async () => { + readPrinterObjectImage.mockResolvedValueOnce({ kind: "ok", value: "data:image/png;base64,x" }); + const r = render(); + await act(async () => { + fireEvent.click(r.getByText(loc.showObject)); + }); + expect(readPrinterObjectImage).toHaveBeenCalledWith(target, pre, media); + expect((r.getByRole("img") as HTMLImageElement).alt).toBe("R:PRE.GRF"); + fireEvent.click(r.getByLabelText(en.app.close)); + readPrinterObjectImage.mockResolvedValueOnce({ kind: "ok", value: null }); + await act(async () => { + fireEvent.click(r.getByText(loc.showObject)); + }); + expect(r.getByRole("alert").textContent).toBe(loc.graphicUnreadable); + }); + + it("lets the printer draw a font sample and says when it drew nothing", async () => { + readPrinterObjectImage.mockResolvedValueOnce({ kind: "ok", value: "data:image/png;base64,x" }); + const r = render(); + await act(async () => { + fireEvent.click(r.getByText(loc.showObject)); + }); + expect(readPrinterObjectImage).toHaveBeenCalledWith(target, font, media); + expect((r.getByRole("img") as HTMLImageElement).alt).toBe("E:CG_TIMES.TTF"); + fireEvent.click(r.getByLabelText(en.app.close)); + readPrinterObjectImage.mockResolvedValueOnce({ kind: "ok", value: null }); + await act(async () => { + fireEvent.click(r.getByText(loc.showObject)); + }); + expect(r.getByRole("alert").textContent).toBe(loc.fontSampleBlank); + }); + + it("names the copy that survives the delete, per what the row knows", () => { + const ask = (extra: Partial) => { + const r = render(); + fireEvent.click(r.getByText(loc.deleteObject)); + const message = r.getByRole("alertdialog").textContent ?? ""; + cleanup(); + return message; + }; + expect(ask({ inSetup: true, hasCopy: true })).toContain(loc.setupReuploadHint); + expect(ask({ hasCopy: true })).toContain(loc.deleteLocalCopyHint); + expect(ask({})).toContain(loc.deleteNoCopyHint); + }); + + it("asks per kind, cancels without sending and reports a failed delete on the row", async () => { + deletePrinterObject.mockResolvedValue({ kind: "unreachable" }); + const r = render(); + fireEvent.click(r.getByText(loc.deleteObject)); + expect(r.getByText(`Delete E:CG_TIMES.TTF from the printer? Labels that use it fall back to another font. ${loc.deleteNoCopyHint}`)).toBeTruthy(); + fireEvent.click(r.getByText(en.app.cancel)); + expect(deletePrinterObject).not.toHaveBeenCalled(); + fireEvent.click(r.getByText(loc.deleteObject)); + await act(async () => { + fireEvent.click(r.getAllByText(loc.deleteObject).at(-1) as HTMLElement); + }); + expect(deletePrinterObject).toHaveBeenCalledWith(target, font); + expect(r.getByRole("alert").textContent).toBe(en.printerSettings.printerStatus.failUnreachable); + cleanup(); + const graphics = render(); + fireEvent.click(graphics.getByText(loc.deleteObject)); + expect(graphics.getByText(`Delete R:PRE.GRF from the printer? Labels that recall it print without it. ${loc.deleteNoCopyHint}`)).toBeTruthy(); + }); + + it("retires a failed delete's message with the listing it was reported against", async () => { + deletePrinterObject.mockResolvedValue({ kind: "unreachable" }); + const r = render(); + fireEvent.click(r.getByText(loc.deleteObject)); + await act(async () => { + fireEvent.click(r.getAllByText(loc.deleteObject).at(-1) as HTMLElement); + }); + expect(r.getByRole("alert")).toBeTruthy(); + act(() => useLabelStore.setState({ printerObjects: { phase: "done", key: "net:172.17.17.175:9100", at: 1, directories: listing } })); + expect(r.queryByRole("alert")).toBeNull(); + }); + + it("offers no delete for a firmware object the printer never releases", () => { + const r = render(); + expect((r.getByText(loc.deleteObject) as HTMLButtonElement).disabled).toBe(true); + expect((r.getByText(loc.showObject) as HTMLButtonElement).disabled).toBe(false); + }); + + it("locks both actions while the channel carries another read", () => { + act(() => useLabelStore.setState({ printerReading: "^HW" })); + const r = render(); + expect([loc.showObject, loc.deleteObject].map((label) => (r.getByText(label) as HTMLButtonElement).disabled)).toEqual([true, true]); + }); +}); diff --git a/src/components/PrinterSettings/PrinterStorage.tsx b/src/components/PrinterSettings/PrinterStorage.tsx new file mode 100644 index 00000000..ee0b0ca1 --- /dev/null +++ b/src/components/PrinterSettings/PrinterStorage.tsx @@ -0,0 +1,157 @@ +import { useState } from "react"; +import { InformationCircleIcon } from "@heroicons/react/16/solid"; +import type { HostObject } from "@zplab/core/lib/hostDirectory"; +import { isWritableDevice } from "@zplab/core/lib/storagePath"; +import { deleteKnowledge, originState, type DeleteKnowledge, type OriginState, type StoredObjectKind, type StoredObjectOrigin } from "@zplab/core/lib/storedObjectOrigins"; +import { isDesktopShell } from "../../lib/platform"; +import { usePrinterListing } from "../../hooks/usePrinterListing"; +import { useT } from "../../hooks/useT"; +import type { Translations } from "../../locales"; +import { formatTemplate } from "../../lib/formatTemplate"; +import type { PrinterOutcome } from "../../lib/printerQuery"; +import type { PrinterObjectsState } from "../../store/slices/printerObjectsSlice"; +import { failureText, readingText } from "../../lib/printerStatusText"; +import { selectPrinterObjects, useLabelStore } from "../../store/labelStore"; +import { ConfirmDialog } from "../ui/ConfirmDialog"; +import { Tooltip } from "../ui/Tooltip"; +import { buttonCls, disabledCls, sectionHeadingCls, zplCommandTagCls } from "../ui/formStyles"; +import { PrinterImageDialog } from "./PrinterImageDialog"; + +const kb = (bytes: number): string => String(bytes === 0 ? 0 : Math.max(1, Math.round(bytes / 1024))); + +export function StoredObjectsHeading() { + const loc = useT().printerSettings.objects; + return ( +
+
+

{loc.listHeading}

+ + + +
+ + ~DY + {isDesktopShell && ^HW} + +
+ ); +} + +export function PrinterStorageBar() { + const t = useT(); + const loc = t.printerSettings.objects; + const status = t.printerSettings.printerStatus; + const state = useLabelStore(selectPrinterObjects); + const step = useLabelStore((s) => s.printerReading); + const read = useLabelStore((s) => s.readPrinterObjects); + const listing = usePrinterListing(); + const line = + step !== undefined + ? readingText(status, step) + : state.phase === "failed" + ? failureText(status, state.failure) + : state.phase === "done" + ? formatTemplate(status.checkedAtFmt, { time: new Date(state.at).toLocaleTimeString() }) + : loc.printerNotRead; + + return ( +
+
+ + + {line} + +
+ {listing && listing.free.length > 0 && ( +

{listing.free.map((f) => formatTemplate(loc.printerFreeFmt, { device: f.device, kb: kb(f.bytesFree) })).join(", ")}

+ )} +
+ ); +} + +const ORIGIN_KEY = { + missingOnPrinter: "originMissing", + notOnPrinter: "originAbsent", + onPrinter: "originOnPrinter", + printerOnly: "originPrinterOnly", +} as const satisfies Record, keyof Translations["printerSettings"]["objects"]>; + +export function PrinterOriginMark({ origin }: { origin: StoredObjectOrigin }) { + const loc = useT().printerSettings.objects; + const state = originState(origin); + if (state === "unread") return null; + return ( + + {loc[ORIGIN_KEY[state]]} + {origin.hostObject && {formatTemplate(loc.objectSizeFmt, { kb: kb(origin.hostObject.size) })}} + + ); +} + +const KNOWLEDGE_KEY = { + setupReuploads: "setupReuploadHint", + localCopy: "deleteLocalCopyHint", + noCopy: "deleteNoCopyHint", +} as const satisfies Record; + +export function PrinterObjectActions({ origin, kind }: { origin: StoredObjectOrigin & { hostObject: HostObject }; kind: StoredObjectKind }) { + const t = useT(); + const loc = t.printerSettings.objects; + const object = origin.hostObject; + const reading = useLabelStore((s) => s.printerReading !== undefined); + const listing = useLabelStore(selectPrinterObjects); + const readImage = useLabelStore((s) => s.readPrinterObjectImage); + const remove = useLabelStore((s) => s.deletePrinterObject); + const [pendingDelete, setPendingDelete] = useState(false); + // The message belongs to the listing it was reported against, so the next read retires it. + const [issue, setIssue] = useState<{ listing: PrinterObjectsState; text: string }>(); + const [image, setImage] = useState | "reading">(); + const writable = isWritableDevice(object.device); + + const show = () => { + setImage("reading"); + // The dialog closed while the read ran, so its result has nowhere to land. + void readImage(object).then((read) => setImage((current) => (current === undefined ? current : read))); + }; + const confirmDelete = () => { + setPendingDelete(false); + setIssue(undefined); + void remove(object).then((failure) => { + const listing = selectPrinterObjects(useLabelStore.getState()); + setIssue(failure ? { listing, text: failureText(t.printerSettings.printerStatus, failure) } : undefined); + }); + }; + + return ( + <> + + {issue?.listing === listing && ( + + {issue.text} + + )} + + + + + + {pendingDelete && ( + setPendingDelete(false)} + /> + )} + {image && setImage(undefined)} />} + + ); +} diff --git a/src/components/PrinterSettings/StoredFontsTab.printer.test.tsx b/src/components/PrinterSettings/StoredFontsTab.printer.test.tsx new file mode 100644 index 00000000..c99e7934 --- /dev/null +++ b/src/components/PrinterSettings/StoredFontsTab.printer.test.tsx @@ -0,0 +1,73 @@ +// @vitest-environment jsdom +import { describe, it, expect, afterEach, beforeEach, vi } from "vitest"; +import { render, cleanup, act } from "@testing-library/react"; +import { loadFontBytes, removeFont } from "@zplab/core/lib/fontCache"; +import { StoredFontsTab } from "./StoredFontsTab"; +import { useLabelStore } from "../../store/labelStore"; +import { DEFAULT_PRINT_TARGET } from "../../lib/printTarget"; +import { fallbackTranslations as en } from "../../locales"; +import type { HostDirectory } from "@zplab/core/lib/hostDirectory"; + +vi.mock("../../lib/platform", async (importOriginal) => ({ ...(await importOriginal>()), isDesktopShell: true })); + +const loc = en.printerSettings.objects; +const fontsLoc = en.printerSettings.fonts; +const object = (device: string, name: string, ext: string, size = 1000) => ({ device, name, ext, size }); +const dir = (device: string, objects: HostDirectory["objects"]): HostDirectory => ({ device, objects, bytesFree: undefined }); +const listed = (directories: HostDirectory[]) => + act(() => useLabelStore.setState({ printerObjects: { phase: "done", key: "net:172.17.17.175:9100", at: 0, directories } })); + +beforeEach(async () => { + await loadFontBytes(new Uint8Array([0, 1, 0, 0]), "E:ARIAL.TTF"); + act(() => + useLabelStore.setState({ + printerProfile: {}, + printerObjects: { phase: "idle" }, + printerReading: undefined, + printTarget: { ...DEFAULT_PRINT_TARGET, host: "172.17.17.175" }, + }), + ); +}); + +afterEach(() => { + cleanup(); + removeFont("E:ARIAL.TTF"); +}); + +describe("StoredFontsTab against the printer", () => { + it("marks each row with where it stands and keeps one row per file", () => { + act(() => useLabelStore.setState({ printerProfile: { setupFonts: [{ path: "E:ARIAL.TTF" }, { path: "R:GONE.TTF" }] } })); + listed([ + dir("R", []), + dir("E", [object("E", "ARIAL", "TTF", 4096), object("E", "CG_TIMES", "TTF")]), + ]); + const r = render(); + expect(r.getAllByTitle(/\.TTF$/).map((el) => el.getAttribute("title"))).toEqual(["E:ARIAL.TTF", "R:GONE.TTF", "E:CG_TIMES.TTF"]); + expect(r.getByText(loc.originOnPrinter)).toBeTruthy(); + expect(r.getByText(loc.originMissing)).toBeTruthy(); + expect(r.getByText(loc.originPrinterOnly)).toBeTruthy(); + expect(r.getByText(loc.objectSizeFmt.replace("{kb}", "4"))).toBeTruthy(); + }); + + it("offers the setup script only for a file whose bytes it has, and the printer actions only for a listed one", () => { + listed([dir("E", [object("E", "CG_TIMES", "TTF")])]); + const r = render(); + // The cached E:ARIAL.TTF can be provisioned, the printer's own font cannot. + expect(r.getAllByLabelText(new RegExp(fontsLoc.uploadToggle))).toHaveLength(1); + expect(r.getAllByText(loc.showObject)).toHaveLength(1); + }); + + it("claims absence only for a drive that answered", () => { + act(() => useLabelStore.setState({ printerProfile: { setupFonts: [{ path: "B:OTHER.TTF" }] } })); + listed([dir("E", [object("E", "ARIAL", "TTF")])]); + const r = render(); + expect(r.queryByText(loc.originMissing)).toBeNull(); + expect(r.getByText(loc.originOnPrinter)).toBeTruthy(); + }); + + it("says nothing about the printer before a read", () => { + const r = render(); + expect(r.getByText(loc.printerNotRead)).toBeTruthy(); + for (const text of [loc.originOnPrinter, loc.originAbsent, loc.originMissing, loc.originPrinterOnly]) expect(r.queryByText(text)).toBeNull(); + }); +}); diff --git a/src/components/PrinterSettings/StoredFontsTab.tsx b/src/components/PrinterSettings/StoredFontsTab.tsx index 8cee200d..5a4d745f 100644 --- a/src/components/PrinterSettings/StoredFontsTab.tsx +++ b/src/components/PrinterSettings/StoredFontsTab.tsx @@ -1,24 +1,26 @@ import { useRef, useState } from "react"; +import { usePrinterListing } from "../../hooks/usePrinterListing"; import { useT } from "../../hooks/useT"; import { Tooltip } from "../ui/Tooltip"; import { FONT_FILE_ACCEPT, cachedFontPath, loadFontBytes } from "@zplab/core/lib/fontCache"; -import { findSetupEntry, withSetupEntry, withoutSetupEntry } from "@zplab/core/lib/setupEntries"; +import { withSetupEntry, withoutSetupEntry } from "@zplab/core/lib/setupEntries"; import { isTrueTypeFileName, prepareFontUpload, printerFontFileName, type FontUploadIssue } from "@zplab/core/lib/customFonts"; import { listsStoredFont } from "@zplab/core/lib/storedObjects"; +import { storedObjectOrigins } from "@zplab/core/lib/storedObjectOrigins"; import { storageKey, storageRefMatchesPath } from "@zplab/core/lib/storagePath"; import { useCachedFonts } from "../../hooks/useCachedFonts"; import { useUpload } from "../../hooks/useUpload"; import { useLabelStore, selectEditorFrozen } from "../../store/labelStore"; import { fontNameIssueText } from "../../lib/fontNameIssueText"; import { isDesktopShell } from "../../lib/platform"; -import { PrinterObjectsSection } from "./PrinterObjectsSection"; -import { buttonCls, disabledCls, sectionHeadingCls } from "../ui/formStyles"; +import { PrinterObjectActions, PrinterOriginMark, PrinterStorageBar, StoredObjectsHeading } from "./PrinterStorage"; +import { buttonCls, disabledCls } from "../ui/formStyles"; import { ConfirmDialog } from "../ui/ConfirmDialog"; /** Why a profile row cannot be provisioned. */ -function rowIssue(path: string, cachedKeys: ReadonlySet): "unshippable" | "missingBytes" | undefined { - if (!isTrueTypeFileName(path)) return "unshippable"; - return cachedKeys.has(storageKey(path)) ? undefined : "missingBytes"; +function rowIssue(key: string, cachedKeys: ReadonlySet): "unshippable" | "missingBytes" | undefined { + if (!isTrueTypeFileName(key)) return "unshippable"; + return cachedKeys.has(key) ? undefined : "missingBytes"; } /** A picked file can supply the bytes only when the upload naming rule keeps this exact path. */ @@ -27,7 +29,7 @@ function repairable(path: string): boolean { return own !== undefined && storageRefMatchesPath(own, path); } -/** Provisioning plus the printer's own listing. Deleting cached fonts stays in the FontManager. */ +/** Deleting cached fonts stays in the FontManager. */ export function StoredFontsTab() { const t = useT(); const fonts = useCachedFonts(); @@ -39,14 +41,23 @@ export function StoredFontsTab() { const frozen = useLabelStore(selectEditorFrozen); // A cache row is named by its printer path, so profile and cache rows share one identity rule. - const cachedPaths = fonts.map(cachedFontPath); + const cachedPaths = fonts.map(cachedFontPath).filter((path) => listsStoredFont(path, setupFonts)); const cachedKeys = new Set(cachedPaths.map(storageKey)); - const rows = [ - ...(setupFonts ?? []).map((f) => ({ path: f.path, inProfile: true, replayed: f.download !== undefined, issue: f.download === undefined ? rowIssue(f.path, cachedKeys) : undefined })), - ...cachedPaths - .filter((path) => listsStoredFont(path, setupFonts) && !findSetupEntry(setupFonts, path)) - .map((path) => ({ path, inProfile: false, replayed: false, issue: undefined })), - ]; + // A replayed upload carries its own bytes in the profile, so it needs no cache row behind it. + const replayedPaths = (setupFonts ?? []).flatMap((f) => (f.download === undefined ? [] : [f.path])); + const replayedKeys = new Set(replayedPaths.map(storageKey)); + const rows = storedObjectOrigins({ + kind: "font", + setupPaths: (setupFonts ?? []).map((f) => f.path), + local: [...cachedPaths, ...replayedPaths].map((path) => ({ path, hasBytes: true })), + listing: usePrinterListing(), + }).map((origin) => { + const replayed = replayedKeys.has(origin.key); + const issue = origin.inSetup && !replayed ? rowIssue(origin.key, cachedKeys) : undefined; + // A printer-only row offers nothing: without bytes here, provisioning has nothing to send. + const control = issue ? "removeEntry" : replayed ? "removeReplayed" : cachedKeys.has(origin.key) ? "provision" : "none"; + return { origin, replayed, issue, control }; + }); const toggle = (path: string, on: boolean) => patchPrinterProfileWith((p) => ({ setupFonts: on ? withSetupEntry(p.setupFonts, { path }) : withoutSetupEntry(p.setupFonts, path) })); @@ -70,12 +81,7 @@ export function StoredFontsTab() { return (
-
-

- {loc.uploadHeading} -

-
-

{loc.uploadHint}

+
- + {uploadIssue && {{ error: loc.uploadError, notAFont: loc.uploadError, ...fontNameIssueText(t), refused: t.printerSettings.frozenHint }[uploadIssue]}}
+ {isDesktopShell && } {rows.length === 0 ? (

{loc.noFonts}

) : (
    - {rows.map(({ path, inProfile, replayed, issue }) => - !issue ? ( + {rows.map(({ origin, replayed, issue, control }) => { + const { path, key, inSetup, hostObject } = origin; + return (
  • - + {path} - {inProfile && shipsToo(path) && {t.delivery.job}} + {issue && {issue === "unshippable" ? loc.unshippableEntry : loc.missingBytes}} + {inSetup && shipsToo(path) && {t.delivery.job}} {replayed && ( {loc.printerFormat} )} - - {replayed ? ( - - ) : ( - - - - )} -
  • - ) : ( -
  • - - - {path} - - - {issue === "unshippable" ? loc.unshippableEntry : loc.missingBytes} - + + {hostObject && } {issue === "missingBytes" && repairable(path) && ( )} - + {control === "removeEntry" && ( + + )} + {control === "removeReplayed" && ( + + )} + {control === "provision" && ( + + + + )}
  • - ), - )} + ); + })}
)}
- {isDesktopShell && } {pendingRemove !== undefined && ( ({ ...(await importOriginal>()), isDesktopShell: true })); + +const loc = en.printerSettings.objects; +const object = (device: string, name: string, ext: string, size = 1000) => ({ device, name, ext, size }); +const dir = (device: string, objects: HostDirectory["objects"]): HostDirectory => ({ device, objects, bytesFree: undefined }); +const listed = (directories: HostDirectory[]) => + act(() => useLabelStore.setState({ printerObjects: { phase: "done", key: "net:172.17.17.175:9100", at: 0, directories } })); + +beforeEach(() => { + act(() => + useLabelStore.setState({ + pages: [{ objects: [] }], + printerProfile: {}, + printerObjects: { phase: "idle" }, + printerReading: undefined, + printTarget: { ...DEFAULT_PRINT_TARGET, host: "172.17.17.175" }, + }), + ); +}); + +afterEach(cleanup); + +describe("StoredGraphicsTab against the printer", () => { + it("lists a profile entry and the printer's own graphics in one list, each with its origin", () => { + act(() => useLabelStore.setState({ printerProfile: { setupGraphics: [{ path: "R:LOGO.GRF", gfa: "^GFA,1,1,1,00" }] } })); + listed([ + dir("R", [object("R", "LOGO", "GRF"), object("R", "LBL", "ZPL")]), + dir("E", [object("E", "CHK06", "PNG", 2203)]), + ]); + const r = render(); + expect(r.getAllByTitle(/^[RE]:/).map((el) => el.getAttribute("title"))).toEqual(["R:LOGO.GRF", "E:CHK06.PNG"]); + expect(r.getByText(loc.originOnPrinter)).toBeTruthy(); + expect(r.getByText(loc.originPrinterOnly)).toBeTruthy(); + expect(r.getAllByText(loc.showObject)).toHaveLength(2); + }); + + it("names a profile entry the printer does not hold", () => { + act(() => useLabelStore.setState({ printerProfile: { setupGraphics: [{ path: "R:LOGO.GRF", gfa: "^GFA,1,1,1,00" }] } })); + listed([dir("R", [])]); + const r = render(); + expect(r.getByText(loc.originMissing)).toBeTruthy(); + expect(r.queryByText(loc.showObject)).toBeNull(); + }); + + it("calls a recall whose bytes are gone the printer's own copy, and says so before deleting it", () => { + const orphan = { + id: "img1", + type: "image", + x: 0, + y: 0, + rotation: 0, + props: { imageId: "", widthDots: 8, heightDots: 4, threshold: 128, storedAs: { device: "R", name: "LOGO", embedInZpl: false } }, + } as unknown as LabelObject; + act(() => useLabelStore.setState({ pages: [{ objects: [orphan] }] })); + listed([dir("R", [object("R", "LOGO", "GRF")])]); + const r = render(); + expect(r.getByText(loc.originPrinterOnly)).toBeTruthy(); + fireEvent.click(r.getByText(loc.deleteObject)); + expect(r.getByRole("alertdialog").textContent).toContain(loc.deleteNoCopyHint); + }); + + it("keeps the local image cache a section of its own", () => { + listed([dir("R", [object("R", "LOGO", "GRF")])]); + const r = render(); + expect(r.getByText(loc.cacheHeading)).toBeTruthy(); + expect(r.getByText(loc.noCached)).toBeTruthy(); + }); +}); diff --git a/src/components/PrinterSettings/StoredGraphicsTab.tsx b/src/components/PrinterSettings/StoredGraphicsTab.tsx index 9c4d36e4..04e5d4be 100644 --- a/src/components/PrinterSettings/StoredGraphicsTab.tsx +++ b/src/components/PrinterSettings/StoredGraphicsTab.tsx @@ -2,23 +2,24 @@ import { useRef, useState } from "react"; import { InformationCircleIcon } from "@heroicons/react/16/solid"; import { Tooltip } from "../ui/Tooltip"; import { ConfirmDialog } from "../ui/ConfirmDialog"; +import { usePrinterListing } from "../../hooks/usePrinterListing"; import { useT } from "../../hooks/useT"; import { useUpload } from "../../hooks/useUpload"; import { useLabelStore, useFileDeletability, forgetHistoryUsing, selectEditorFrozen, type DeleteBlock } from "../../store/labelStore"; import { encodeGraphicFile } from "@zplab/core/lib/imageToZpl"; -import { sanitizeStorageName, setupEntryKey, uploadedGraphicPath } from "@zplab/core/lib/storagePath"; -import { findSetupEntry, setupEntryHoldsOther, withSetupEntry, withoutSetupEntry } from "@zplab/core/lib/setupEntries"; -import { buttonCls, disabledCls, sectionHeadingCls, zplCommandTagCls } from "../ui/formStyles"; +import { sanitizeStorageName, uploadedGraphicPath } from "@zplab/core/lib/storagePath"; +import { setupEntryHoldsOther, withSetupEntry, withoutSetupEntry } from "@zplab/core/lib/setupEntries"; +import { buttonCls, disabledCls, sectionHeadingCls } from "../ui/formStyles"; import { useCachedImages } from "../../hooks/useCachedImages"; -import { canSendSetupGraphic, setupGraphicFits, setupGraphicOf, setupGraphicState } from "@zplab/core/registry/image"; +import { canSendSetupGraphic, hasLocalGraphicBytes, setupGraphicFits, setupGraphicOf, setupGraphicState } from "@zplab/core/registry/image"; import { storedGraphicRows, type StoredGraphicRow } from "@zplab/core/lib/storedObjects"; +import { storedObjectOrigins } from "@zplab/core/lib/storedObjectOrigins"; import { removeImage } from "@zplab/core/lib/imageCache"; import { imageUsage } from "@zplab/core/lib/imageUsage"; import type { SetupGraphic } from "@zplab/core/types/PrinterProfile"; import { isDesktopShell } from "../../lib/platform"; -import { PrinterObjectsSection } from "./PrinterObjectsSection"; +import { PrinterObjectActions, PrinterOriginMark, PrinterStorageBar, StoredObjectsHeading } from "./PrinterStorage"; -/** Provisioning, the local image cache and the printer's own listing. Whether a job ships its own bytes stays with the object. */ export function StoredGraphicsTab() { const t = useT(); const pages = useLabelStore((s) => s.pages); @@ -28,7 +29,13 @@ export function StoredGraphicsTab() { const loc = t.printerSettings.objects; const rows = storedGraphicRows(pages); - const profileOnly = (setupGraphics ?? []).filter((g) => !rows.has(setupEntryKey(g))); + const setupPaths = (setupGraphics ?? []).map((g) => g.path); + const local = [ + ...[...rows.entries()].map(([path, row]) => ({ path, hasBytes: hasLocalGraphicBytes(row.props) })), + // A profile entry always carries its own bytes. + ...setupPaths.map((path) => ({ path, hasBytes: true })), + ]; + const origins = storedObjectOrigins({ kind: "graphic", setupPaths, local, listing: usePrinterListing() }); const put = (entry: SetupGraphic) => patchPrinterProfileWith((p) => ({ setupGraphics: withSetupEntry(p.setupGraphics, entry) })); const drop = (path: string) => patchPrinterProfileWith((p) => ({ setupGraphics: withoutSetupEntry(p.setupGraphics, path) })); @@ -82,17 +89,7 @@ export function StoredGraphicsTab() { return (
-
-
-

- {loc.uploadHeading} -

- - - -
- ~DY -
+
- + @@ -117,22 +114,57 @@ export function StoredGraphicsTab() { )}
- {rows.size === 0 && profileOnly.length === 0 ? ( + {isDesktopShell && } + {origins.length === 0 ? (

{loc.noGraphics}

) : (
    - {[...rows.entries()].map(([path, row]) => { + {origins.map((origin) => { + const { key, path, hostObject } = origin; + // `uploadKey` already returns the normalised key, so an origin finds its row. + const row = rows.get(key); + const actions = hostObject && ; + if (!row) { + return ( +
  • + + + {path} + + {origin.inSetup && {loc.fromProfile}} + + + + {actions} + {origin.inSetup && ( + + )} + +
  • + ); + } const { props } = row; const state = setupGraphicState(props, setupGraphics); - const hasEntry = findSetupEntry(setupGraphics, path) !== undefined; + const hasEntry = origin.inSetup; const orphan = state === "none" && props.storedAs?.embedInZpl === false; // Bytes double up when the entry and the job both ship, so the row names it. const shipsToo = hasEntry && props.storedAs?.embedInZpl !== false; const resend = state === "stale" ? loc.staleEntry : state === "unknown" ? loc.unverifiedEntry : null; - const refused = sendIssue?.path === path && sendIssue.cache === props._gfaCache ? sendIssue.fit : null; + const refused = sendIssue?.path === key && sendIssue.cache === props._gfaCache ? sendIssue.fit : null; return (
  • @@ -142,7 +174,7 @@ export function StoredGraphicsTab() { {refused ? ( {refused === "tooLarge" ? loc.tooLarge : loc.tooWide} ) : resend && canSendSetupGraphic(props) ? ( - ) : resend ? ( @@ -154,49 +186,30 @@ export function StoredGraphicsTab() { ) : shipsToo ? ( {t.delivery.job} ) : null} + + + + {actions} + + + - - -
  • ); })} - {profileOnly.map((entry) => ( -
  • - - - {entry.path} - - {loc.fromProfile} - - -
  • - ))}
)}
- {isDesktopShell && }
diff --git a/src/hooks/usePrinterListing.ts b/src/hooks/usePrinterListing.ts new file mode 100644 index 00000000..855acb89 --- /dev/null +++ b/src/hooks/usePrinterListing.ts @@ -0,0 +1,7 @@ +import { hostListing, type HostListing } from "@zplab/core/lib/storedObjectOrigins"; +import { selectPrinterObjects, useLabelStore } from "../store/labelStore"; + +export function usePrinterListing(): HostListing | undefined { + const state = useLabelStore(selectPrinterObjects); + return state.phase === "done" ? hostListing(state.directories) : undefined; +} diff --git a/src/lib/printerObjects.test.ts b/src/lib/printerObjects.test.ts index 58c6d35c..7cf16718 100644 --- a/src/lib/printerObjects.test.ts +++ b/src/lib/printerObjects.test.ts @@ -76,14 +76,14 @@ describe("readPrinterObjects", () => { queryPrinter.mockImplementation((_t: unknown, zpl: string) => Promise.resolve(listingOf(zpl))); const steps: string[] = []; const result = await readPrinterObjects(network, (step) => steps.push(step)); - expect(steps).toEqual(["^HWR:*.*", "^HWE:*.*", "^HWB:*.*", "^HWA:*.*"]); + expect(steps).toEqual(["^HWR:*.*", "^HWE:*.*", "^HWB:*.*", "^HWA:*.*", "^HWZ:*.*"]); expect(queryPrinter).toHaveBeenNthCalledWith(2, network, "^XA^HWE:*.*^XZ"); - expect(result).toMatchObject({ kind: "ok", value: [{ device: "R", objects: [{ name: "PRE" }] }, { device: "E" }, { device: "B" }, { device: "A" }] }); + expect(result).toMatchObject({ kind: "ok", value: [{ device: "R", objects: [{ name: "PRE" }] }, { device: "E" }, { device: "B" }, { device: "A" }, { device: "Z" }] }); }); it("leaves out a drive the printer does not list and fails when no drive parsed", async () => { queryPrinter.mockImplementation((_t: unknown, zpl: string) => Promise.resolve(zpl.includes("HWA") ? { kind: "ok", value: "" } : listingOf(zpl))); - expect(await readPrinterObjects(network)).toMatchObject({ kind: "ok", value: [{ device: "R" }, { device: "E" }, { device: "B" }] }); + expect(await readPrinterObjects(network)).toMatchObject({ kind: "ok", value: [{ device: "R" }, { device: "E" }, { device: "B" }, { device: "Z" }] }); queryPrinter.mockResolvedValue({ kind: "ok", value: "PRINTER STATUS" }); expect(await readPrinterObjects(network)).toEqual({ kind: "unparsed" }); }); diff --git a/src/lib/printerObjects.ts b/src/lib/printerObjects.ts index dda40aed..e9c8aa50 100644 --- a/src/lib/printerObjects.ts +++ b/src/lib/printerObjects.ts @@ -1,7 +1,6 @@ import { fontSampleZpl, type SampleMedia } from "@zplab/core/lib/fontSample"; import { rasterFromGfa } from "@zplab/core/lib/gfaDecode"; -import { hostObjectKind, hostObjectPath, parseHostDirectories, parseHostGraphic, type HostDirectory, type HostGraphic, type HostObject } from "@zplab/core/lib/hostDirectory"; -import { STORAGE_DEVICES } from "@zplab/core/lib/storagePath"; +import { HOST_LISTING_DEVICES, hostObjectKind, hostObjectPath, parseHostDirectories, parseHostGraphic, type HostDirectory, type HostGraphic, type HostObject } from "@zplab/core/lib/hostDirectory"; import { bitmapToDataUrl, fetchPrinterPreview } from "./printerPreview"; import { queryPrinter, type PrinterOutcome, type PrinterQueryFailure } from "./printerQuery"; import type { QueryTarget } from "./printTarget"; @@ -12,7 +11,7 @@ import { contentBounds, cropBitmap, type PrinterBitmap } from "./zebraGraphic"; /** One ^HW per drive and per query, so a slow drive cannot cut the next one off at the idle gap. A drive that goes silent ends the walk and keeps the earlier listings. */ export async function readPrinterObjects(target: QueryTarget, onStep?: (command: string) => void): Promise> { const directories: HostDirectory[] = []; - for (const device of STORAGE_DEVICES) { + for (const device of HOST_LISTING_DEVICES) { const command = `^HW${device}:*.*`; onStep?.(command); const res = await queryPrinter(target, `^XA${command}^XZ`); diff --git a/src/locales/ar.ts b/src/locales/ar.ts index f9e673f6..f918a4e4 100644 --- a/src/locales/ar.ts +++ b/src/locales/ar.ts @@ -698,8 +698,7 @@ const ar = { fontLinksOverLimitFmt: 'أكثر من 5 روابط لـ: {bases}. الطابعة تتجاهل الفائض بصمت.', }, fonts: { - uploadHeading: 'مرفوع بواسطة نص الإعداد', - uploadHint: 'اختر الخطوط المرفوعة التي يرسلها نص الإعداد إلى الطابعة.', + uploadHint: 'اختر ملف خط ليرسله نص الإعداد. يُحفظ أيضًا في الذاكرة المؤقتة المحلية حتى تستطيع لوحة التصميم معاينته.', noFonts: 'لم يتم رفع أي خطوط بعد.', uploadToggle: 'إرسال عند الإعداد', missingBytes: 'الخط مفقود. حمّله أو احذف الإدخال.', @@ -723,8 +722,7 @@ const ar = { fontCacheTypeInternal: 'داخلي (خطوط آسيوية)', }, objects: { - uploadHeading: 'مرفوع بواسطة نص الإعداد', - uploadHint: 'اختر الرسومات المخزّنة التي يرفعها نص الإعداد مرة واحدة. اضبط تسليم الصورة على «مرة واحدة في نص الإعداد» لتكتفي المهام باستدعائها.', + uploadHint: 'اختر ملف صورة ليرفعه نص الإعداد مرة واحدة. اضبط تسليم الصورة على «مرة واحدة في نص الإعداد» لتكتفي المهام باستدعائها.', noGraphics: 'لا توجد رسومات مخزّنة بعد. ارفع واحدة هنا أو فعّل تخزين الطابعة لصورة.', uploadToggle: 'إرسال عند الإعداد', fromProfile: 'محفوظ في ملف الطابعة هذا', @@ -753,11 +751,8 @@ const ar = { cacheDeleteUnusedConfirmFmt: 'هل تريد حذف {n} صورة لا يستخدمها هذا المستند ولا سجل التراجع الخاص به؟ التصاميم التي حفظتها سابقًا وتستخدمها ستفقدها.', cacheDeleteHistoryOne: 'سيحذف ذلك أيضاً الخطوة الوحيدة في سجل التراجع التي تستخدمها.', cacheDeleteHistoryManyFmt: 'سيحذف ذلك أيضاً {n} خطوات في سجل التراجع تستخدمها.', - printerHeading: 'على الطابعة', - printerHint: 'ما يبلغ عنه الطابعة من ذاكرته. اقرأه لمقارنته بنص الإعداد.', readPrinter: 'قراءة الطابعة', printerNotRead: 'لم تُقرأ بعد.', - printerEmpty: 'الطابعة لا تُبلغ عن أي عناصر من هذا النوع.', printerFreeFmt: '{device}: {kb} KB متاحة', objectSizeFmt: '{kb} KB', showObject: 'عرض', @@ -767,6 +762,16 @@ const ar = { deleteGraphicConfirmFmt: 'هل تريد حذف {path} من الطابعة؟ الملصقات التي تستدعيه تُطبع بدونه.', deleteFontConfirmFmt: 'هل تريد حذف {path} من الطابعة؟ الملصقات التي تستخدمه تتراجع إلى خط آخر.', setupReuploadHint: 'نص الإعداد يسرده ويرفعه مرة أخرى في تشغيله التالي.', + listHeading: 'تخزين الطابعة', + listHint: 'كل ملف من هذا النوع يعرفه التطبيق، من نص الإعداد ومن نسخك المحلية.', + listHintPrinter: 'اقرأ الطابعة لإضافة ما تحتفظ به.', + originMissing: 'في نص الإعداد، ليس على الطابعة', + originAbsent: 'ليس على الطابعة', + originOnPrinter: 'على الطابعة', + originPrinterOnly: 'على الطابعة فقط', + deleteLocalCopyHint: 'تبقى النسخة المحلية هنا.', + deleteNoCopyHint: 'لا شيء هنا يحتفظ بنسخة. يعود عنصر المصنع مع إعادة تحميل البرنامج الثابت. الملف المرفوع لا يعود.', + firmwareObject: 'تحتفظ الطابعة بعناصر البرنامج الثابت الخاصة بها ولا تتخلى عنها.', }, identity: { printerName: 'اسم الطابعة', diff --git a/src/locales/bg.ts b/src/locales/bg.ts index 7a030bd8..31e23065 100644 --- a/src/locales/bg.ts +++ b/src/locales/bg.ts @@ -698,8 +698,7 @@ const bg = { fontLinksOverLimitFmt: 'Повече от 5 връзки за: {bases}. Принтерът мълчаливо игнорира излишъка.', }, fonts: { - uploadHeading: 'Качено от скрипта за настройка', - uploadHint: 'Изберете кои качени шрифтове скриптът за настройка изпраща към принтера.', + uploadHint: 'Изберете файл с шрифт, който скриптът за настройка да изпрати. Той се запазва и в локалния кеш, за да може платното за дизайн да го визуализира.', noFonts: 'Все още няма качени шрифтове.', uploadToggle: 'Изпрати при настройка', missingBytes: 'Шрифтът липсва. Качете го или премахнете записа.', @@ -723,8 +722,7 @@ const bg = { fontCacheTypeInternal: 'Вътрешен (азиатски шрифтове)', }, objects: { - uploadHeading: 'Качено от скрипта за настройка', - uploadHint: 'Изберете кои съхранени графики скриптът за настройка качва еднократно. Задайте доставката на изображението на „Веднъж в скрипта за настройка“, за да могат заданията само да го извикват.', + uploadHint: 'Изберете файл с изображение, който скриптът за настройка да качи еднократно. Задайте доставката на изображението на „Веднъж в скрипта за настройка“, за да могат заданията само да го извикват.', noGraphics: 'Все още няма съхранени графики. Качете една тук или активирайте паметта на принтера за изображение.', uploadToggle: 'Изпрати при настройка', fromProfile: 'Запазено в този профил на принтера', @@ -753,11 +751,8 @@ const bg = { cacheDeleteUnusedConfirmFmt: 'Да се изтрият ли {n} изображения, които не използва нито този документ, нито историята му на отмяна? Дизайните, които сте запазили по-рано и ги използват, ще ги загубят.', cacheDeleteHistoryOne: 'Това също ще премахне единствената стъпка в историята на отмяна, която го използва.', cacheDeleteHistoryManyFmt: 'Това също ще премахне {n} стъпки в историята на отмяна, които го използват.', - printerHeading: 'На принтера', - printerHint: 'Какво отчита принтерът от паметта си. Прочетете го, за да го сравните със скрипта за настройка.', readPrinter: 'Прочитане на принтера', printerNotRead: 'Още не е прочетено.', - printerEmpty: 'Принтерът не отчита никакви обекти от този вид.', printerFreeFmt: '{device}: {kb} KB свободни', objectSizeFmt: '{kb} KB', showObject: 'Показване', @@ -767,6 +762,16 @@ const bg = { deleteGraphicConfirmFmt: 'Да се изтрие ли {path} от принтера? Етикетите, които го извикват, се отпечатват без него.', deleteFontConfirmFmt: 'Да се изтрие ли {path} от принтера? Етикетите, които го използват, преминават към друг шрифт.', setupReuploadHint: 'Скриптът за настройка го изброява и го качва отново при следващото изпълнение.', + listHeading: 'Памет на принтера', + listHint: 'Всеки файл от този вид, който приложението разпознава, от скрипта за настройка и от локалните ви копия.', + listHintPrinter: 'Прочетете принтера, за да добавите това, което пази.', + originMissing: 'В скрипта за настройка, но не на принтера', + originAbsent: 'Не е на принтера', + originOnPrinter: 'На принтера', + originPrinterOnly: 'Само на принтера', + deleteLocalCopyHint: 'Локалното копие остава тук.', + deleteNoCopyHint: 'Нищо тук не пази копие. Фабричен обект се възстановява при презареждане на фърмуера. Качен файл не се възстановява.', + firmwareObject: 'Принтерът пази собствените си обекти на фърмуера и не се разделя с тях.', }, identity: { printerName: 'Име на принтера', diff --git a/src/locales/cs.ts b/src/locales/cs.ts index deb4edaa..533df23f 100644 --- a/src/locales/cs.ts +++ b/src/locales/cs.ts @@ -698,8 +698,7 @@ const cs = { fontLinksOverLimitFmt: 'Více než 5 odkazů pro: {bases}. Tiskárna tiše ignoruje přebytek.', }, fonts: { - uploadHeading: 'Nahráno instalačním skriptem', - uploadHint: 'Vyberte, která nahraná písma odešle instalační skript do tiskárny.', + uploadHint: 'Vyberte soubor s písmem, který instalační skript odešle. Uloží se i do místní mezipaměti, aby ho mohlo plátno zobrazit v náhledu.', noFonts: 'Zatím nejsou nahraná žádná písma.', uploadToggle: 'Odeslat při nastavení', missingBytes: 'Písmo chybí. Nahrajte je nebo odeberte záznam.', @@ -723,8 +722,7 @@ const cs = { fontCacheTypeInternal: 'Interní (asijská písma)', }, objects: { - uploadHeading: 'Nahráno instalačním skriptem', - uploadHint: 'Vyberte, které uložené obrázky instalační skript nahraje jednou. Nastavte doručení obrázku na „Jednou v instalačním skriptu“, aby ho úlohy jen vyvolávaly.', + uploadHint: 'Vyberte soubor s obrázkem, který instalační skript jednou nahraje. Nastavte doručení obrázku na „Jednou v instalačním skriptu“, aby ho úlohy jen vyvolávaly.', noGraphics: 'Zatím nejsou uložené žádné obrázky. Nahrajte sem nějaký nebo aktivujte úložiště tiskárny u obrázku.', uploadToggle: 'Odeslat při nastavení', fromProfile: 'Uloženo v tomto profilu tiskárny', @@ -753,11 +751,8 @@ const cs = { cacheDeleteUnusedConfirmFmt: 'Smazat {n} obrázků, které nepoužívá tento dokument ani jeho historie zpět? Dříve uložené návrhy, které je používají, o ně přijdou.', cacheDeleteHistoryOne: 'Tím se navíc odstraní jediný krok v historii zpět, který ji používá.', cacheDeleteHistoryManyFmt: 'Tím se navíc odstraní {n} kroků v historii zpět, které ji používají.', - printerHeading: 'Na tiskárně', - printerHint: 'Co tiskárna hlásí ze své paměti. Přečtěte si to a porovnejte s instalačním skriptem.', readPrinter: 'Načíst tiskárnu', printerNotRead: 'Zatím nepřečteno.', - printerEmpty: 'Tiskárna nehlásí žádné objekty tohoto druhu.', printerFreeFmt: '{device}: {kb} KB volné', objectSizeFmt: '{kb} KB', showObject: 'Zobrazit', @@ -767,6 +762,16 @@ const cs = { deleteGraphicConfirmFmt: 'Smazat {path} z tiskárny? Štítky, které jej vyvolávají, se vytisknou bez něj.', deleteFontConfirmFmt: 'Smazat {path} z tiskárny? Štítky, které ho používají, přejdou na jiné písmo.', setupReuploadHint: 'Instalační skript ho uvádí v seznamu a při dalším běhu ho nahraje znovu.', + listHeading: 'Úložiště tiskárny', + listHint: 'Každý soubor tohoto druhu, o kterém aplikace ví, z instalačního skriptu a z vašich místních kopií.', + listHintPrinter: 'Přečtěte tiskárnu, abyste přidali, co uchovává.', + originMissing: 'V instalačním skriptu, ne na tiskárně', + originAbsent: 'Není na tiskárně', + originOnPrinter: 'Na tiskárně', + originPrinterOnly: 'Pouze na tiskárně', + deleteLocalCopyHint: 'Místní kopie zůstává tady.', + deleteNoCopyHint: 'Nic tady neukládá kopii. Tovární objekt se vrátí po novém nahrání firmwaru. Nahraný soubor se nevrátí.', + firmwareObject: 'Tiskárna si ponechává vlastní objekty firmwaru a nevzdává se jich.', }, identity: { printerName: 'Název tiskárny', diff --git a/src/locales/da.ts b/src/locales/da.ts index 2a030577..4fe6f9b5 100644 --- a/src/locales/da.ts +++ b/src/locales/da.ts @@ -698,8 +698,7 @@ const da = { fontLinksOverLimitFmt: 'Mere end 5 links for: {bases}. Printeren ignorerer stille overskydende.', }, fonts: { - uploadHeading: 'Uploadet af opsætningsscriptet', - uploadHint: 'Vælg, hvilke uploadede skrifttyper opsætningsscriptet sender til printeren.', + uploadHint: 'Vælg en skrifttypefil, som opsætningsscriptet skal sende. Den lægges også i den lokale cache, så kanvasset kan vise en forhåndsvisning af den.', noFonts: 'Ingen skrifttyper er uploadet endnu.', uploadToggle: 'Send ved opsætning', missingBytes: 'Skrifttype mangler. Upload den eller fjern posten.', @@ -723,8 +722,7 @@ const da = { fontCacheTypeInternal: 'Intern (asiatiske skrifttyper)', }, objects: { - uploadHeading: 'Uploadet af opsætningsscriptet', - uploadHint: 'Vælg, hvilken gemt grafik opsætningsscriptet uploader én gang. Sæt billedets levering til »Én gang i opsætningsscriptet«, så job kun henter den frem.', + uploadHint: 'Vælg en billedfil, som opsætningsscriptet skal uploade én gang. Sæt billedets levering til »Én gang i opsætningsscriptet«, så job kun henter den frem.', noGraphics: 'Ingen gemt grafik endnu. Upload en her, eller aktivér printer-lager på et billede.', uploadToggle: 'Send ved opsætning', fromProfile: 'Gemt i denne printerprofil', @@ -753,11 +751,8 @@ const da = { cacheDeleteUnusedConfirmFmt: 'Slet {n} billeder, som hverken dette dokument eller dets fortryd-historik bruger? Designs, du har gemt tidligere, og som bruger dem, mister dem.', cacheDeleteHistoryOne: 'Dette fjerner også det ene trin i fortryd-historikken, der bruger det.', cacheDeleteHistoryManyFmt: 'Dette fjerner også {n} trin i fortryd-historikken, der bruger det.', - printerHeading: 'På printeren', - printerHint: 'Hvad printeren rapporterer fra sin hukommelse. Læs det for at sammenligne med opsætningsscriptet.', readPrinter: 'Læs printer', printerNotRead: 'Endnu ikke læst.', - printerEmpty: 'Printeren rapporterer ingen objekter af denne type.', printerFreeFmt: '{device}: {kb} KB fri', objectSizeFmt: '{kb} KB', showObject: 'Vis', @@ -767,6 +762,16 @@ const da = { deleteGraphicConfirmFmt: 'Slet {path} fra printeren? Etiketter, der henter det frem, udskrives uden det.', deleteFontConfirmFmt: 'Slet {path} fra printeren? Etiketter, der bruger den, falder tilbage til en anden skrifttype.', setupReuploadHint: 'Opsætningsscriptet lister den og uploader den igen ved næste kørsel.', + listHeading: 'Printerlager', + listHint: 'Hver fil af denne type, appen kender til, fra opsætningsscriptet og fra dine lokale kopier.', + listHintPrinter: 'Læs printeren for at tilføje, hvad den gemmer.', + originMissing: 'I opsætningsscriptet, ikke på printeren', + originAbsent: 'Ikke på printeren', + originOnPrinter: 'På printeren', + originPrinterOnly: 'Kun på printeren', + deleteLocalCopyHint: 'Den lokale kopi bliver her.', + deleteNoCopyHint: 'Ingenting her har en kopi. Et fabriksobjekt kommer tilbage med en firmware-genindlæsning. En upload kommer ikke tilbage.', + firmwareObject: 'Printeren beholder sine egne firmware-objekter og giver dem ikke fra sig.', }, identity: { printerName: 'Printernavn', diff --git a/src/locales/de.ts b/src/locales/de.ts index 1a069846..49ad6124 100644 --- a/src/locales/de.ts +++ b/src/locales/de.ts @@ -698,8 +698,7 @@ const de = { fontLinksOverLimitFmt: 'Mehr als 5 Verknüpfungen für: {bases}. Drucker ignoriert Überlauf stillschweigend.', }, fonts: { - uploadHeading: 'Vom Setup-Skript hochgeladen', - uploadHint: 'Wähle aus, welche hochgeladenen Schriftarten das Setup-Skript an den Drucker sendet.', + uploadHint: 'Wähle eine Schriftdatei, die das Setup-Skript sendet. Sie landet zugleich im lokalen Cache, damit die Zeichenfläche sie als Vorschau zeigen kann.', noFonts: 'Noch keine Schriftarten hochgeladen.', uploadToggle: 'Beim Setup senden', missingBytes: 'Schrift fehlt. Neu hochladen oder Eintrag entfernen.', @@ -723,8 +722,7 @@ const de = { fontCacheTypeInternal: 'Intern (asiatische Schriften)', }, objects: { - uploadHeading: 'Vom Setup-Skript hochgeladen', - uploadHint: 'Wähle aus, welche gespeicherten Grafiken das Setup-Skript einmalig hochlädt. Stelle die Bereitstellung des Bildes auf „Einmalig im Setup-Skript“, damit Druckjobs es nur noch aufrufen.', + uploadHint: 'Wähle eine Bilddatei, die das Setup-Skript einmalig hochlädt. Stelle die Bereitstellung des Bildes auf „Einmalig im Setup-Skript“, damit Druckjobs es nur noch aufrufen.', noGraphics: 'Noch keine gespeicherten Grafiken. Lade hier eine hoch oder aktiviere den Drucker-Speicher für ein Bild.', uploadToggle: 'Beim Setup senden', fromProfile: 'In diesem Druckerprofil gespeichert', @@ -753,11 +751,8 @@ const de = { cacheDeleteUnusedConfirmFmt: '{n} Bilder löschen, die weder dieses Dokument noch seine Undo-Historie benutzen? Früher gespeicherte Designs, die sie benutzen, verlieren sie.', cacheDeleteHistoryOne: 'Dabei entfällt auch der eine Schritt im Undo-Verlauf, der es benutzt.', cacheDeleteHistoryManyFmt: 'Dabei entfallen auch {n} Schritte im Undo-Verlauf, die es benutzen.', - printerHeading: 'Auf dem Drucker', - printerHint: 'Was der Drucker aus seinem Speicher meldet. Lies es, um es mit dem Setup-Skript zu vergleichen.', readPrinter: 'Drucker lesen', printerNotRead: 'Noch nicht gelesen.', - printerEmpty: 'Der Drucker meldet keine Objekte dieser Art.', printerFreeFmt: '{device}: {kb} KB frei', objectSizeFmt: '{kb} KB', showObject: 'Anzeigen', @@ -767,6 +762,16 @@ const de = { deleteGraphicConfirmFmt: '{path} vom Drucker löschen? Etiketten, die es aufrufen, drucken dann ohne es.', deleteFontConfirmFmt: '{path} vom Drucker löschen? Etiketten, die ihn verwenden, weichen auf eine andere Schriftart aus.', setupReuploadHint: 'Das Setup-Skript listet es und lädt es beim nächsten Lauf erneut hoch.', + listHeading: 'Druckerspeicher', + listHint: 'Jede Datei dieser Art, die die App kennt, aus dem Setup-Skript und aus deinen lokalen Kopien.', + listHintPrinter: 'Lies den Drucker, um hinzuzufügen, was er speichert.', + originMissing: 'Im Setup-Skript, nicht auf dem Drucker', + originAbsent: 'Nicht auf dem Drucker', + originOnPrinter: 'Auf dem Drucker', + originPrinterOnly: 'Nur auf dem Drucker', + deleteLocalCopyHint: 'Die lokale Kopie bleibt hier.', + deleteNoCopyHint: 'Nichts hier bewahrt eine Kopie. Ein Werksobjekt kehrt mit einem Firmware-Reload zurück. Ein Upload kommt nicht zurück.', + firmwareObject: 'Der Drucker behält seine eigenen Firmware-Objekte und gibt sie nicht frei.', }, identity: { printerName: 'Druckername', diff --git a/src/locales/el.ts b/src/locales/el.ts index c8ba8132..db1943ad 100644 --- a/src/locales/el.ts +++ b/src/locales/el.ts @@ -698,8 +698,7 @@ const el = { fontLinksOverLimitFmt: 'Περισσότεροι από 5 σύνδεσμοι για: {bases}. Ο εκτυπωτής αγνοεί σιωπηλά την υπέρβαση.', }, fonts: { - uploadHeading: 'Ανέβηκε από το σενάριο εγκατάστασης', - uploadHint: 'Επιλέξτε ποιες ανεβασμένες γραμματοσειρές στέλνει το σενάριο εγκατάστασης στον εκτυπωτή.', + uploadHint: 'Επιλέξτε ένα αρχείο γραμματοσειράς για να το στείλει το σενάριο εγκατάστασης. Αποθηκεύεται και στην τοπική προσωρινή μνήμη, ώστε ο καμβάς να μπορεί να την προεπισκοπήσει.', noFonts: 'Δεν έχουν ανέβει γραμματοσειρές ακόμη.', uploadToggle: 'Αποστολή κατά την εγκατάσταση', missingBytes: 'Λείπει η γραμματοσειρά. Ανεβάστε την ή αφαιρέστε την καταχώρηση.', @@ -723,8 +722,7 @@ const el = { fontCacheTypeInternal: 'Εσωτερική (ασιατικές γραμματοσειρές)', }, objects: { - uploadHeading: 'Ανέβηκε από το σενάριο εγκατάστασης', - uploadHint: 'Επιλέξτε ποια αποθηκευμένα γραφικά ανεβάζει μία φορά το σενάριο εγκατάστασης. Ορίστε την παράδοση της εικόνας σε «Μία φορά στο σενάριο εγκατάστασης», ώστε οι εργασίες απλώς να την ανακαλούν.', + uploadHint: 'Επιλέξτε ένα αρχείο εικόνας για να το ανεβάσει μία φορά το σενάριο εγκατάστασης. Ορίστε την παράδοση της εικόνας σε «Μία φορά στο σενάριο εγκατάστασης», ώστε οι εργασίες απλώς να την ανακαλούν.', noGraphics: 'Δεν υπάρχουν ακόμη αποθηκευμένα γραφικά. Ανεβάστε ένα εδώ ή ενεργοποιήστε την αποθήκευση εκτυπωτή σε μια εικόνα.', uploadToggle: 'Αποστολή κατά την εγκατάσταση', fromProfile: 'Διατηρείται σε αυτό το προφίλ εκτυπωτή', @@ -753,11 +751,8 @@ const el = { cacheDeleteUnusedConfirmFmt: 'Διαγραφή {n} εικόνων που δεν χρησιμοποιεί ούτε αυτό το έγγραφο ούτε το ιστορικό αναιρέσεών του; Τα σχέδια που αποθηκεύσατε παλαιότερα και τις χρησιμοποιούν θα τις χάσουν.', cacheDeleteHistoryOne: 'Αυτό αφαιρεί επίσης το ένα βήμα στο ιστορικό αναιρέσεων που τη χρησιμοποιεί.', cacheDeleteHistoryManyFmt: 'Αυτό αφαιρεί επίσης {n} βήματα στο ιστορικό αναιρέσεων που τη χρησιμοποιούν.', - printerHeading: 'Στον εκτυπωτή', - printerHint: 'Τι αναφέρει ο εκτυπωτής από τη μνήμη του. Διαβάστε το για να το συγκρίνετε με το σενάριο εγκατάστασης.', readPrinter: 'Ανάγνωση εκτυπωτή', printerNotRead: 'Δεν έχει διαβαστεί ακόμα.', - printerEmpty: 'Ο εκτυπωτής δεν αναφέρει αντικείμενα αυτού του είδους.', printerFreeFmt: '{device}: {kb} KB ελεύθερα', objectSizeFmt: '{kb} KB', showObject: 'Εμφάνιση', @@ -767,6 +762,16 @@ const el = { deleteGraphicConfirmFmt: 'Διαγραφή του {path} από τον εκτυπωτή; Οι ετικέτες που το ανακαλούν εκτυπώνονται χωρίς αυτό.', deleteFontConfirmFmt: 'Διαγραφή του {path} από τον εκτυπωτή; Οι ετικέτες που το χρησιμοποιούν επιστρέφουν σε άλλη γραμματοσειρά.', setupReuploadHint: 'Το σενάριο εγκατάστασης το καταγράφει και το ανεβάζει ξανά στην επόμενη εκτέλεσή του.', + listHeading: 'Αποθήκευση εκτυπωτή', + listHint: 'Κάθε αρχείο αυτού του είδους που γνωρίζει η εφαρμογή, από το σενάριο εγκατάστασης και από τα τοπικά σου αντίγραφα.', + listHintPrinter: 'Διαβάστε τον εκτυπωτή για να προσθέσετε όσα διατηρεί.', + originMissing: 'Στο σενάριο εγκατάστασης, όχι στον εκτυπωτή', + originAbsent: 'Όχι στον εκτυπωτή', + originOnPrinter: 'Στον εκτυπωτή', + originPrinterOnly: 'Μόνο στον εκτυπωτή', + deleteLocalCopyHint: 'Το τοπικό αντίγραφο παραμένει εδώ.', + deleteNoCopyHint: 'Τίποτα εδώ δεν κρατά αντίγραφο. Ένα εργοστασιακό αντικείμενο επανέρχεται με επαναφόρτωση του firmware. Ένα ανεβασμένο αρχείο δεν επανέρχεται.', + firmwareObject: 'Ο εκτυπωτής διατηρεί τα δικά του αντικείμενα firmware και δεν τα αφήνει να φύγουν.', }, identity: { printerName: 'Όνομα εκτυπωτή', diff --git a/src/locales/en.ts b/src/locales/en.ts index 4d992b8e..1360a42a 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -698,8 +698,7 @@ const en = { fontLinksOverLimitFmt: 'More than 5 links for: {bases}. Printer silently ignores overflow.', }, fonts: { - uploadHeading: 'Uploaded by the setup script', - uploadHint: 'Choose which uploaded fonts the setup script sends to the printer.', + uploadHint: 'Pick a font file for the setup script to send. It also goes into the local cache, so the canvas can preview it.', noFonts: 'No fonts uploaded yet.', uploadToggle: 'Send at setup', missingBytes: 'Font missing. Upload it or remove this entry.', @@ -723,8 +722,7 @@ const en = { fontCacheTypeInternal: 'Internal (Asian fonts)', }, objects: { - uploadHeading: 'Uploaded by the setup script', - uploadHint: "Choose which stored graphics the setup script uploads once. Set the image's delivery to \"Once in the setup script\" so jobs only recall it.", + uploadHint: 'Pick an image file for the setup script to upload once. Set an image delivery to "Once in the setup script" so jobs only recall it.', noGraphics: 'No stored graphics yet. Upload one here, or activate printer storage on an image.', uploadToggle: 'Send at setup', fromProfile: 'Kept in this printer profile', @@ -753,11 +751,8 @@ const en = { cacheDeleteUnusedConfirmFmt: 'Delete {n} images nothing in this document or its undo history uses? Designs you saved earlier that use them will lose them.', cacheDeleteHistoryOne: 'This also drops the one step in the undo history that uses it.', cacheDeleteHistoryManyFmt: 'This also drops {n} steps in the undo history that use it.', - printerHeading: 'On the printer', - printerHint: 'What the printer reports from its memory. Read it to compare with the setup script.', readPrinter: 'Read printer', printerNotRead: 'Not read yet.', - printerEmpty: 'The printer reports no objects of this kind.', printerFreeFmt: '{device}: {kb} KB free', objectSizeFmt: '{kb} KB', showObject: 'Show', @@ -767,6 +762,16 @@ const en = { deleteGraphicConfirmFmt: 'Delete {path} from the printer? Labels that recall it print without it.', deleteFontConfirmFmt: 'Delete {path} from the printer? Labels that use it fall back to another font.', setupReuploadHint: 'The setup script lists it and uploads it again on its next run.', + listHeading: 'Printer storage', + listHint: 'Every file of this kind the app knows about, from the setup script and from your local copies.', + listHintPrinter: 'Read the printer to add what it holds.', + originMissing: 'In the setup script, not on the printer', + originAbsent: 'Not on the printer', + originOnPrinter: 'On the printer', + originPrinterOnly: 'Only on the printer', + deleteLocalCopyHint: 'The local copy stays here.', + deleteNoCopyHint: 'Nothing here holds a copy. A factory object comes back with a firmware reload. An upload does not come back.', + firmwareObject: 'The printer keeps its own firmware objects and does not let them go.', }, identity: { printerName: 'Printer name', diff --git a/src/locales/es.ts b/src/locales/es.ts index ef96e563..1ea49d7e 100644 --- a/src/locales/es.ts +++ b/src/locales/es.ts @@ -698,8 +698,7 @@ const es = { fontLinksOverLimitFmt: 'Más de 5 enlaces para: {bases}. La impresora ignora silenciosamente el exceso.', }, fonts: { - uploadHeading: 'Subido por el script de configuración', - uploadHint: 'Elige qué fuentes subidas envía el script de configuración a la impresora.', + uploadHint: 'Elige un archivo de fuente para que el script de configuración lo envíe. También se guarda en la caché local, para que el lienzo pueda previsualizarla.', noFonts: 'Aún no hay fuentes subidas.', uploadToggle: 'Enviar en configuración', missingBytes: 'Falta la fuente. Súbela o elimina la entrada.', @@ -723,8 +722,7 @@ const es = { fontCacheTypeInternal: 'Interno (fuentes asiáticas)', }, objects: { - uploadHeading: 'Subido por el script de configuración', - uploadHint: 'Elige qué gráficos guardados sube una sola vez el script de configuración. Ajusta la entrega de la imagen a «Una vez en el script de configuración» para que los trabajos solo la invoquen.', + uploadHint: 'Elige un archivo de imagen para que el script de configuración lo suba una sola vez. Ajusta la entrega de la imagen a «Una vez en el script de configuración» para que los trabajos solo la invoquen.', noGraphics: 'Aún no hay gráficos guardados. Sube uno aquí o activa el almacenamiento de impresora en una imagen.', uploadToggle: 'Enviar en configuración', fromProfile: 'Guardado en este perfil de impresora', @@ -753,11 +751,8 @@ const es = { cacheDeleteUnusedConfirmFmt: '¿Eliminar {n} imágenes que ni este documento ni su historial de deshacer usan? Los diseños que guardaste antes y las usan las perderán.', cacheDeleteHistoryOne: 'Esto también elimina el único paso en el historial de deshacer que la usa.', cacheDeleteHistoryManyFmt: 'Esto también elimina {n} pasos en el historial de deshacer que la usan.', - printerHeading: 'En la impresora', - printerHint: 'Lo que la impresora informa desde su memoria. Léelo para compararlo con el script de configuración.', readPrinter: 'Leer impresora', printerNotRead: 'Aún no leído.', - printerEmpty: 'La impresora no informa de ningún objeto de este tipo.', printerFreeFmt: '{device}: {kb} KB libres', objectSizeFmt: '{kb} KB', showObject: 'Mostrar', @@ -767,6 +762,16 @@ const es = { deleteGraphicConfirmFmt: '¿Eliminar {path} de la impresora? Las etiquetas que lo invocan se imprimen sin él.', deleteFontConfirmFmt: '¿Eliminar {path} de la impresora? Las etiquetas que lo usan recurren a otra fuente.', setupReuploadHint: 'El script de configuración lo incluye en la lista y lo vuelve a subir en su próxima ejecución.', + listHeading: 'Almacenamiento de la impresora', + listHint: 'Todos los archivos de este tipo que la aplicación conoce, del script de configuración y de tus copias locales.', + listHintPrinter: 'Lee la impresora para añadir lo que guarda.', + originMissing: 'En el script de configuración, no en la impresora', + originAbsent: 'No está en la impresora', + originOnPrinter: 'En la impresora', + originPrinterOnly: 'Solo en la impresora', + deleteLocalCopyHint: 'La copia local se queda aquí.', + deleteNoCopyHint: 'Nada aquí guarda una copia. Un objeto de fábrica vuelve con una recarga del firmware. Un archivo subido no vuelve.', + firmwareObject: 'La impresora conserva sus propios objetos de firmware y no los suelta.', }, identity: { printerName: 'Nombre de la impresora', diff --git a/src/locales/et.ts b/src/locales/et.ts index 6d0c136e..ae0fda38 100644 --- a/src/locales/et.ts +++ b/src/locales/et.ts @@ -698,8 +698,7 @@ const et = { fontLinksOverLimitFmt: 'Üle 5 lingi: {bases}. Printer ignoreerib ületäidet vaikselt.', }, fonts: { - uploadHeading: 'Seadistusskripti poolt üles laaditud', - uploadHint: 'Vali, millised üleslaaditud fondid saadab seadistusskript printerisse.', + uploadHint: 'Vali fondifail, mille seadistusskript saadab. See salvestub ka kohalikku vahemällu, et lõuend saaks seda eelvaadata.', noFonts: 'Veel pole fonte üles laaditud.', uploadToggle: 'Saada seadistusel', missingBytes: 'Font puudub. Laadi üles või eemalda kirje.', @@ -723,8 +722,7 @@ const et = { fontCacheTypeInternal: 'Sisemine (Aasia fondid)', }, objects: { - uploadHeading: 'Seadistusskripti poolt üles laaditud', - uploadHint: 'Vali, millise salvestatud graafika laadib seadistusskript ühe korra üles. Määra pildi edastuseks „Üks kord seadistusskriptis“, et tööd seda ainult välja kutsuksid.', + uploadHint: 'Vali pildifail, mille seadistusskript laadib üles ühe korra. Määra pildi edastuseks „Üks kord seadistusskriptis“, et tööd seda ainult välja kutsuksid.', noGraphics: 'Salvestatud graafikat veel pole. Laadi siia üks üles või aktiveeri pildi juures printeri salvestus.', uploadToggle: 'Saada seadistusel', fromProfile: 'Hoitakse selles printeriprofiilis', @@ -753,11 +751,8 @@ const et = { cacheDeleteUnusedConfirmFmt: 'Kustutada {n} pilti, mida ei kasuta ei see dokument ega selle tagasivõtmise ajalugu? Varem salvestatud kujundused, mis neid kasutavad, kaotavad need.', cacheDeleteHistoryOne: 'Selle käigus kustub ka üks samm tagasivõtmise ajaloos, mis seda kasutab.', cacheDeleteHistoryManyFmt: 'Selle käigus kustub ka {n} sammu tagasivõtmise ajaloos, mis seda kasutavad.', - printerHeading: 'Printeris', - printerHint: 'Mida printer teatab oma mälust. Loe see, et võrrelda seadistusskriptiga.', readPrinter: 'Loe printerit', printerNotRead: 'Pole veel loetud.', - printerEmpty: 'Printer ei teata ühtegi sellist objekti.', printerFreeFmt: '{device}: {kb} KB vaba', objectSizeFmt: '{kb} KB', showObject: 'Näita', @@ -767,6 +762,16 @@ const et = { deleteGraphicConfirmFmt: 'Kustutada {path} printerist? Etiketid, mis selle välja kutsuvad, prinditakse selleta.', deleteFontConfirmFmt: 'Kustutada {path} printerist? Etiketid, mis seda kasutavad, lähevad üle teisele fondile.', setupReuploadHint: 'Seadistusskript loetleb selle ja laadib selle järgmisel käitamisel uuesti üles.', + listHeading: 'Printeri salvestus', + listHint: 'Kõik selle liigi failid, mida rakendus tunneb, seadistusskriptist ja sinu kohalikest koopiatest.', + listHintPrinter: 'Loe printerit, et lisada, mida ta hoiab.', + originMissing: 'Seadistusskriptis, mitte printeris', + originAbsent: 'Ei ole printeris', + originOnPrinter: 'Printeris', + originPrinterOnly: 'Ainult printeris', + deleteLocalCopyHint: 'Kohalik koopia jääb siia.', + deleteNoCopyHint: 'Siin ei hoia midagi koopiat. Tehase objekt tuleb tagasi püsivara uuesti laadimisega. Üles laaditud fail ei tule tagasi.', + firmwareObject: 'Printer hoiab oma püsivara objekte ja ei anna neid käest.', }, identity: { printerName: 'Printeri nimi', diff --git a/src/locales/fa.ts b/src/locales/fa.ts index 12a39af0..cac2e21e 100644 --- a/src/locales/fa.ts +++ b/src/locales/fa.ts @@ -698,8 +698,7 @@ const fa = { fontLinksOverLimitFmt: 'بیش از ۵ پیوند برای: {bases}. چاپگر اضافی را بی‌صدا نادیده می‌گیرد.', }, fonts: { - uploadHeading: 'بارگذاری‌شده توسط اسکریپت راه‌اندازی', - uploadHint: 'انتخاب کنید کدام فونت‌های بارگذاری‌شده توسط اسکریپت راه‌اندازی به چاپگر ارسال شوند.', + uploadHint: 'یک فایل فونت انتخاب کنید تا اسکریپت راه‌اندازی آن را ارسال کند. این فایل همچنین در حافظهٔ پنهان محلی ذخیره می‌شود تا بوم بتواند آن را پیش‌نمایش دهد.', noFonts: 'هنوز فونتی بارگذاری نشده است.', uploadToggle: 'ارسال هنگام راه‌اندازی', missingBytes: 'فونت موجود نیست. بارگذاری کنید یا ورودی را حذف کنید.', @@ -723,8 +722,7 @@ const fa = { fontCacheTypeInternal: 'داخلی (فونت‌های آسیایی)', }, objects: { - uploadHeading: 'بارگذاری‌شده توسط اسکریپت راه‌اندازی', - uploadHint: 'انتخاب کنید کدام گرافیک‌های ذخیره‌شده یک بار توسط اسکریپت راه‌اندازی بارگذاری شوند. تحویل تصویر را روی «یک بار در اسکریپت راه‌اندازی» تنظیم کنید تا کارها فقط آن را فراخوانی کنند.', + uploadHint: 'یک فایل تصویر انتخاب کنید تا اسکریپت راه‌اندازی یک‌بار آن را بارگذاری کند. تحویل تصویر را روی «یک‌بار در اسکریپت راه‌اندازی» تنظیم کنید تا کارها فقط آن را فراخوانی کنند.', noGraphics: 'هنوز گرافیک ذخیره‌شده‌ای وجود ندارد. یکی را اینجا بارگذاری کنید یا ذخیره‌سازی چاپگر را برای یک تصویر فعال کنید.', uploadToggle: 'ارسال هنگام راه‌اندازی', fromProfile: 'در این نمایه چاپگر نگه داشته می‌شود', @@ -753,11 +751,8 @@ const fa = { cacheDeleteUnusedConfirmFmt: '{n} تصویری که نه این سند و نه تاریخچهٔ واگرد آن استفاده نمی‌کند حذف شوند؟ طرح‌هایی که پیش‌تر ذخیره کرده‌اید و از آن‌ها استفاده می‌کنند آن‌ها را از دست می‌دهند.', cacheDeleteHistoryOne: 'این کار تنها مرحله‌ای از تاریخچهٔ واگرد را که از آن استفاده می‌کند نیز حذف می‌کند.', cacheDeleteHistoryManyFmt: 'این کار {n} مرحله از تاریخچهٔ واگرد را که از آن استفاده می‌کنند نیز حذف می‌کند.', - printerHeading: 'روی چاپگر', - printerHint: 'آنچه چاپگر از حافظه‌اش گزارش می‌دهد. آن را بخوانید تا با اسکریپت راه‌اندازی مقایسه کنید.', readPrinter: 'خواندن چاپگر', printerNotRead: 'هنوز خوانده نشده است.', - printerEmpty: 'چاپگر هیچ شیئی از این نوع گزارش نمی‌دهد.', printerFreeFmt: '{device}: {kb} KB آزاد', objectSizeFmt: '{kb} KB', showObject: 'نمایش', @@ -767,6 +762,16 @@ const fa = { deleteGraphicConfirmFmt: '{path} از چاپگر حذف شود؟ برچسب‌هایی که آن را فراخوانی می‌کنند بدون آن چاپ می‌شوند.', deleteFontConfirmFmt: '{path} از چاپگر حذف شود؟ برچسب‌هایی که از آن استفاده می‌کنند به فونت دیگری برمی‌گردند.', setupReuploadHint: 'اسکریپت راه‌اندازی آن را فهرست می‌کند و در اجرای بعدی دوباره بارگذاری می‌کند.', + listHeading: 'حافظه چاپگر', + listHint: 'هر فایلی از این نوع که برنامه می‌شناسد، از اسکریپت راه‌اندازی و از نسخه‌های محلی‌تان.', + listHintPrinter: 'چاپگر را بخوانید تا آنچه نگه می‌دارد را اضافه کنید.', + originMissing: 'در اسکریپت راه‌اندازی، نه روی چاپگر', + originAbsent: 'روی چاپگر نیست', + originOnPrinter: 'روی چاپگر', + originPrinterOnly: 'فقط روی چاپگر', + deleteLocalCopyHint: 'نسخه محلی همین‌جا باقی می‌ماند.', + deleteNoCopyHint: 'هیچ‌چیز در اینجا نسخه‌ای نگه نمی‌دارد. یک شیء کارخانه‌ای با بازنشانی فریمور برمی‌گردد. فایل بارگذاری‌شده برنمی‌گردد.', + firmwareObject: 'چاپگر اشیاء فریمور خودش را نگه می‌دارد و اجازه نمی‌دهد از بین بروند.', }, identity: { printerName: 'نام چاپگر', diff --git a/src/locales/fi.ts b/src/locales/fi.ts index ea622831..71d55162 100644 --- a/src/locales/fi.ts +++ b/src/locales/fi.ts @@ -698,8 +698,7 @@ const fi = { fontLinksOverLimitFmt: 'Yli 5 linkkiä kohteelle: {bases}. Tulostin ohittaa ylivuodon hiljaisesti.', }, fonts: { - uploadHeading: 'Asennusskriptin lähettämä', - uploadHint: 'Valitse, mitkä ladatut fontit asennusskripti lähettää tulostimeen.', + uploadHint: 'Valitse fonttitiedosto, jonka asennusskripti lähettää. Se tallentuu myös paikalliseen välimuistiin, jotta kangas voi esikatsella sitä.', noFonts: 'Fontteja ei ole vielä ladattu.', uploadToggle: 'Lähetä asennuksessa', missingBytes: 'Fontti puuttuu. Lataa se tai poista merkintä.', @@ -723,8 +722,7 @@ const fi = { fontCacheTypeInternal: 'Sisäinen (aasialaiset fontit)', }, objects: { - uploadHeading: 'Asennusskriptin lähettämä', - uploadHint: 'Valitse, mitkä tallennetut grafiikat asennusskripti lähettää kerran. Aseta kuvan toimitukseksi ”Kerran asennusskriptissä”, jotta työt vain hakevat sen.', + uploadHint: 'Valitse kuvatiedosto, jonka asennusskripti lataa kerran. Aseta kuvan toimitukseksi ”Kerran asennusskriptissä”, jotta työt vain hakevat sen.', noGraphics: 'Tallennettuja grafiikoita ei vielä ole. Lataa tähän yksi tai ota tulostimen tallennus käyttöön kuvalle.', uploadToggle: 'Lähetä asennuksessa', fromProfile: 'Säilytetään tässä tulostinprofiilissa', @@ -753,11 +751,8 @@ const fi = { cacheDeleteUnusedConfirmFmt: 'Poistetaanko {n} kuvaa, joita ei käytä tämä asiakirja eikä sen kumoamishistoria? Aiemmin tallennetut rakenteet, jotka käyttävät niitä, menettävät ne.', cacheDeleteHistoryOne: 'Tämä poistaa myös ainoan vaiheen kumoamishistoriassa, joka käyttää sitä.', cacheDeleteHistoryManyFmt: 'Tämä poistaa myös {n} vaihetta kumoamishistoriassa, jotka käyttävät sitä.', - printerHeading: 'Tulostimessa', - printerHint: 'Mitä tulostin ilmoittaa muististaan. Lue se verrataksesi asennusskriptiin.', readPrinter: 'Lue tulostin', printerNotRead: 'Ei vielä luettu.', - printerEmpty: 'Tulostin ei ilmoita tämän tyyppisiä objekteja.', printerFreeFmt: '{device}: {kb} KB vapaana', objectSizeFmt: '{kb} KB', showObject: 'Näytä', @@ -767,6 +762,16 @@ const fi = { deleteGraphicConfirmFmt: 'Poistetaanko {path} tulostimesta? Etiketit, jotka hakevat sen, tulostuvat sitä ilman.', deleteFontConfirmFmt: 'Poistetaanko {path} tulostimesta? Etiketit, jotka käyttävät sitä, siirtyvät toiseen fonttiin.', setupReuploadHint: 'Asennusskripti listaa sen ja lähettää sen uudelleen seuraavalla ajolla.', + listHeading: 'Tulostimen tallennustila', + listHint: 'Kaikki tämän tyyppiset tiedostot, jotka sovellus tunnistaa, asennusskriptistä ja paikallisista kopioistasi.', + listHintPrinter: 'Lue tulostin lisätäksesi sen, mitä se pitää hallussaan.', + originMissing: 'Asennusskriptissä, ei tulostimessa', + originAbsent: 'Ei tulostimessa', + originOnPrinter: 'Tulostimessa', + originPrinterOnly: 'Vain tulostimessa', + deleteLocalCopyHint: 'Paikallinen kopio säilyy tässä.', + deleteNoCopyHint: 'Mikään tässä ei säilytä kopiota. Tehtaan objekti palautuu laiteohjelmiston uudelleenlatauksella. Lataus ei palaudu.', + firmwareObject: 'Tulostin pitää omat laiteohjelmisto-objektinsa eikä päästä niistä irti.', }, identity: { printerName: 'Tulostimen nimi', diff --git a/src/locales/fr.ts b/src/locales/fr.ts index c62c1be8..f3162a25 100644 --- a/src/locales/fr.ts +++ b/src/locales/fr.ts @@ -698,8 +698,7 @@ const fr = { fontLinksOverLimitFmt: "Plus de 5 liens pour : {bases}. L'imprimante ignore silencieusement le dépassement.", }, fonts: { - uploadHeading: "Téléversé par le script d'installation", - uploadHint: "Choisissez quelles polices téléversées le script d'installation envoie à l'imprimante.", + uploadHint: "Choisissez un fichier de police que le script d'installation envoie. Il va aussi dans le cache local, pour que le canevas puisse le prévisualiser.", noFonts: "Aucune police téléversée pour l'instant.", uploadToggle: "Envoyer à l'installation", missingBytes: "Police manquante. Téléversez-la ou supprimez l'entrée.", @@ -723,8 +722,7 @@ const fr = { fontCacheTypeInternal: 'Interne (polices asiatiques)', }, objects: { - uploadHeading: "Téléversé par le script d'installation", - uploadHint: "Choisissez quels graphiques stockés le script d'installation téléverse une seule fois. Réglez la livraison de l'image sur « Une fois dans le script d'installation » pour que les travaux se contentent de la rappeler.", + uploadHint: "Choisissez un fichier image que le script d'installation téléverse une seule fois. Réglez une livraison d'image sur « Une fois dans le script d'installation » pour que les travaux se contentent de la rappeler.", noGraphics: "Aucun graphique stocké pour l'instant. Téléversez-en un ici ou activez le stockage de l'imprimante sur une image.", uploadToggle: "Envoyer à l'installation", fromProfile: "Conservé dans ce profil d'imprimante", @@ -753,11 +751,8 @@ const fr = { cacheDeleteUnusedConfirmFmt: "Supprimer {n} images que ni ce document ni son historique d'annulation n'utilisent ? Les designs enregistrés précédemment qui les utilisent les perdront.", cacheDeleteHistoryOne: "Cela supprime aussi l'unique étape de l'historique d'annulation qui l'utilise.", cacheDeleteHistoryManyFmt: "Cela supprime aussi {n} étapes de l'historique d'annulation qui l'utilisent.", - printerHeading: "Sur l'imprimante", - printerHint: "Ce que l'imprimante indique à partir de sa mémoire. Lisez-le pour le comparer au script d'installation.", readPrinter: "Lire l'imprimante", printerNotRead: 'Pas encore lu.', - printerEmpty: "L'imprimante ne signale aucun objet de ce type.", printerFreeFmt: '{device} : {kb} KB libres', objectSizeFmt: '{kb} KB', showObject: 'Afficher', @@ -767,6 +762,16 @@ const fr = { deleteGraphicConfirmFmt: "Supprimer {path} de l'imprimante ? Les étiquettes qui le rappellent s'impriment sans lui.", deleteFontConfirmFmt: "Supprimer {path} de l'imprimante ? Les étiquettes qui l'utilisent basculent vers une autre police.", setupReuploadHint: "Le script d'installation le liste et le téléverse à nouveau lors de sa prochaine exécution.", + listHeading: "Stockage de l'imprimante", + listHint: "Chaque fichier de ce type que l'application connaît, provenant du script d'installation et de vos copies locales.", + listHintPrinter: "Lisez l'imprimante pour ajouter ce qu'elle détient.", + originMissing: "Dans le script d'installation, pas sur l'imprimante", + originAbsent: "Pas sur l'imprimante", + originOnPrinter: "Sur l'imprimante", + originPrinterOnly: "Uniquement sur l'imprimante", + deleteLocalCopyHint: 'La copie locale reste ici.', + deleteNoCopyHint: "Rien ici ne détient de copie. Un objet d'usine revient avec une réinstallation du firmware. Un téléversement ne revient pas.", + firmwareObject: "L'imprimante garde ses propres objets firmware et ne les laisse pas partir.", }, identity: { printerName: 'Nom de l\'imprimante', diff --git a/src/locales/he.ts b/src/locales/he.ts index 11fd58e1..d13b4c46 100644 --- a/src/locales/he.ts +++ b/src/locales/he.ts @@ -698,8 +698,7 @@ const he = { fontLinksOverLimitFmt: 'יותר מ-5 קישורים עבור: {bases}. המדפסת מתעלמת בשקט מהעודף.', }, fonts: { - uploadHeading: 'הועלה על ידי סקריפט ההתקנה', - uploadHint: 'בחר אילו גופנים שהועלו ישלח סקריפט ההתקנה למדפסת.', + uploadHint: 'בחר קובץ גופן שסקריפט ההתקנה ישלח. הוא גם נכנס למטמון המקומי, כך שהקנבס יוכל להציג תצוגה מקדימה שלו.', noFonts: 'עדיין לא הועלו גופנים.', uploadToggle: 'שלח בהתקנה', missingBytes: 'הגופן חסר. העלה אותו או הסר את הרשומה.', @@ -723,8 +722,7 @@ const he = { fontCacheTypeInternal: 'פנימי (גופנים אסייתיים)', }, objects: { - uploadHeading: 'הועלה על ידי סקריפט ההתקנה', - uploadHint: 'בחר איזו גרפיקה שמורה סקריפט ההתקנה יעלה פעם אחת. הגדר את האספקה של התמונה ל"פעם אחת בסקריפט ההתקנה" כדי שעבודות ההדפסה רק יקראו לה.', + uploadHint: 'בחר קובץ תמונה שסקריפט ההתקנה יעלה פעם אחת. הגדר אספקת תמונה ל"פעם אחת בסקריפט ההתקנה" כדי שעבודות רק יקראו לה.', noGraphics: 'עדיין אין גרפיקה שמורה. העלה כאן אחת או הפעל אחסון מדפסת עבור תמונה.', uploadToggle: 'שלח בהתקנה', fromProfile: 'נשמר בפרופיל מדפסת זה', @@ -753,11 +751,8 @@ const he = { cacheDeleteUnusedConfirmFmt: 'למחוק {n} תמונות שלא המסמך הזה ולא היסטוריית הביטולים שלו משתמשים בהן? עיצובים ששמרת בעבר ומשתמשים בהן יאבדו אותן.', cacheDeleteHistoryOne: 'פעולה זו גם תמחק את השלב היחיד בהיסטוריית הביטולים שמשתמש בה.', cacheDeleteHistoryManyFmt: 'פעולה זו גם תמחק {n} שלבים בהיסטוריית הביטולים שמשתמשים בה.', - printerHeading: 'במדפסת', - printerHint: 'מה שהמדפסת מדווחת מהזיכרון שלה. קרא אותו כדי להשוות אותו לסקריפט ההתקנה.', readPrinter: 'קרא מדפסת', printerNotRead: 'עדיין לא נקרא.', - printerEmpty: 'המדפסת לא מדווחת על אובייקטים מהסוג הזה.', printerFreeFmt: '{device}: {kb} KB פנויים', objectSizeFmt: '{kb} KB', showObject: 'הצג', @@ -767,6 +762,16 @@ const he = { deleteGraphicConfirmFmt: 'למחוק את {path} מהמדפסת? תוויות שקוראות לו יודפסו בלעדיו.', deleteFontConfirmFmt: 'למחוק את {path} מהמדפסת? תוויות שמשתמשות בו יעברו לגופן אחר.', setupReuploadHint: 'סקריפט ההתקנה מפרט אותו ומעלה אותו שוב בהפעלה הבאה שלו.', + listHeading: 'אחסון המדפסת', + listHint: 'כל קובץ מהסוג הזה שהאפליקציה מכירה, מסקריפט ההתקנה ומהעותקים המקומיים שלך.', + listHintPrinter: 'קרא את המדפסת כדי להוסיף את מה שהיא מחזיקה.', + originMissing: 'בסקריפט ההתקנה, לא במדפסת', + originAbsent: 'לא במדפסת', + originOnPrinter: 'במדפסת', + originPrinterOnly: 'רק במדפסת', + deleteLocalCopyHint: 'העותק המקומי נשאר כאן.', + deleteNoCopyHint: 'שום דבר כאן לא מחזיק עותק. אובייקט יצרן חוזר עם טעינה מחדש של הקושחה. קובץ שהועלה לא חוזר.', + firmwareObject: 'המדפסת שומרת על אובייקטי הקושחה שלה ולא משחררת אותם.', }, identity: { printerName: 'שם המדפסת', diff --git a/src/locales/hr.ts b/src/locales/hr.ts index 35814e03..9f0b58c1 100644 --- a/src/locales/hr.ts +++ b/src/locales/hr.ts @@ -698,8 +698,7 @@ const hr = { fontLinksOverLimitFmt: 'Više od 5 poveznica za: {bases}. Pisač tiho zanemaruje višak.', }, fonts: { - uploadHeading: 'Učitano instalacijskom skriptom', - uploadHint: 'Odaberite koje učitane fontove instalacijska skripta šalje na pisač.', + uploadHint: 'Odaberite datoteku fonta koju instalacijska skripta šalje. Ona također odlazi u lokalnu predmemoriju, tako da je platno može pregledati.', noFonts: 'Još nije učitan nijedan font.', uploadToggle: 'Pošalji pri postavljanju', missingBytes: 'Font nedostaje. Učitajte ga ili uklonite unos.', @@ -723,8 +722,7 @@ const hr = { fontCacheTypeInternal: 'Interni (azijski fontovi)', }, objects: { - uploadHeading: 'Učitano instalacijskom skriptom', - uploadHint: 'Odaberite koje pohranjene grafike instalacijska skripta učitava jednom. Postavite isporuku slike na „Jednom u instalacijskoj skripti” kako bi je zadaci samo pozivali.', + uploadHint: 'Odaberite datoteku slike koju instalacijska skripta učitava jednom. Postavite isporuku slike na „Jednom u instalacijskoj skripti” kako bi je zadaci samo pozivali.', noGraphics: 'Još nema pohranjenih grafika. Ovdje prenesite jednu ili aktivirajte pohranu pisača za sliku.', uploadToggle: 'Pošalji pri postavljanju', fromProfile: 'Čuva se u ovom profilu pisača', @@ -753,11 +751,8 @@ const hr = { cacheDeleteUnusedConfirmFmt: 'Izbrisati {n} slika koje ne koristi ni ovaj dokument ni njegova povijest poništavanja? Ranije spremljeni dizajni koji ih koriste izgubit će ih.', cacheDeleteHistoryOne: 'Time će se izbrisati i jedini korak u povijesti poništavanja koji je koristi.', cacheDeleteHistoryManyFmt: 'Time će se izbrisati i {n} koraka u povijesti poništavanja koji je koriste.', - printerHeading: 'Na pisaču', - printerHint: 'Što pisač prijavljuje iz svoje memorije. Pročitajte to kako biste usporedili s instalacijskom skriptom.', readPrinter: 'Pročitaj pisač', printerNotRead: 'Još nije pročitano.', - printerEmpty: 'Pisač ne prijavljuje objekte ove vrste.', printerFreeFmt: '{device}: {kb} KB slobodno', objectSizeFmt: '{kb} KB', showObject: 'Prikaži', @@ -767,6 +762,16 @@ const hr = { deleteGraphicConfirmFmt: 'Izbrisati {path} s pisača? Naljepnice koje ga pozivaju ispisuju se bez njega.', deleteFontConfirmFmt: 'Izbrisati {path} s pisača? Naljepnice koje ga koriste prelaze na drugi font.', setupReuploadHint: 'Instalacijska skripta ga navodi na popisu i ponovno ga učitava kod sljedećeg pokretanja.', + listHeading: 'Pohrana pisača', + listHint: 'Svaka datoteka ove vrste o kojoj aplikacija zna, iz instalacijske skripte i iz vaših lokalnih kopija.', + listHintPrinter: 'Pročitajte pisač da dodate ono što čuva.', + originMissing: 'U instalacijskoj skripti, nije na pisaču', + originAbsent: 'Nije na pisaču', + originOnPrinter: 'Na pisaču', + originPrinterOnly: 'Samo na pisaču', + deleteLocalCopyHint: 'Lokalna kopija ostaje ovdje.', + deleteNoCopyHint: 'Ništa ovdje ne čuva kopiju. Fabrički objekt vraća se ponovnim učitavanjem firmvera. Učitana datoteka se ne vraća.', + firmwareObject: 'Pisač čuva svoje objekte firmvera i ne pušta ih.', }, identity: { printerName: 'Naziv pisača', diff --git a/src/locales/hu.ts b/src/locales/hu.ts index aa0b04ed..5ee6b7d5 100644 --- a/src/locales/hu.ts +++ b/src/locales/hu.ts @@ -698,8 +698,7 @@ const hu = { fontLinksOverLimitFmt: 'Több mint 5 hivatkozás ehhez: {bases}. A nyomtató csendben figyelmen kívül hagyja a túlcsordulást.', }, fonts: { - uploadHeading: 'Feltöltve a beállító szkript által', - uploadHint: 'Válaszd ki, mely feltöltött betűtípusokat küldje a beállító szkript a nyomtatóra.', + uploadHint: 'Válassz egy betűtípus-fájlt, amelyet a beállító szkript elküld. Ez a helyi gyorsítótárba is bekerül, hogy a vászon előnézetet mutathasson róla.', noFonts: 'Még nincs feltöltött betűtípus.', uploadToggle: 'Küldés beállításkor', missingBytes: 'Hiányzó betűtípus. Töltsd fel vagy távolítsd el a bejegyzést.', @@ -723,8 +722,7 @@ const hu = { fontCacheTypeInternal: 'Belső (ázsiai betűtípusok)', }, objects: { - uploadHeading: 'Feltöltve a beállító szkript által', - uploadHint: 'Válaszd ki, mely tárolt grafikákat tölti fel egyszer a beállító szkript. Állítsd a kép továbbítását „Egyszer a beállító szkriptben” értékre, hogy a feladatok csak előhívják.', + uploadHint: 'Válassz egy képfájlt, amelyet a beállító szkript egyszer feltölt. Állítsd a kép továbbítását „Egyszer a beállító szkriptben” értékre, hogy a feladatok csak előhívják.', noGraphics: 'Még nincs tárolt grafika. Tölts fel ide egyet, vagy kapcsold be a nyomtató tárhelyét egy képnél.', uploadToggle: 'Küldés beállításkor', fromProfile: 'Ebben a nyomtatóprofilban marad', @@ -753,11 +751,8 @@ const hu = { cacheDeleteUnusedConfirmFmt: 'Törli azt a {n} képet, amelyet sem ez a dokumentum, sem a visszavonási előzményei nem használnak? A korábban mentett tervek, amelyek használják őket, elveszítik.', cacheDeleteHistoryOne: 'Ez egyben törli az egyetlen lépést a visszavonási előzményekben, amely ezt használja.', cacheDeleteHistoryManyFmt: 'Ez egyben töröl {n} lépést a visszavonási előzményekben, amelyek ezt használják.', - printerHeading: 'A nyomtatón', - printerHint: 'Amit a nyomtató jelent a memóriájából. Olvasd be, hogy összehasonlíthasd a beállító szkripttel.', readPrinter: 'Nyomtató beolvasása', printerNotRead: 'Még nincs beolvasva.', - printerEmpty: 'A nyomtató nem jelent ilyen típusú objektumot.', printerFreeFmt: '{device}: {kb} KB szabad', objectSizeFmt: '{kb} KB', showObject: 'Megjelenítés', @@ -767,6 +762,16 @@ const hu = { deleteGraphicConfirmFmt: 'Törli a {path} elemet a nyomtatóról? A rá hivatkozó címkék nélküle nyomtatnak.', deleteFontConfirmFmt: 'Törli a {path} elemet a nyomtatóról? Az ezt használó címkék másik betűtípusra váltanak.', setupReuploadHint: 'A beállító szkript felsorolja, és a következő futásakor újra feltölti.', + listHeading: 'Nyomtató tárhelye', + listHint: 'Minden ilyen típusú fájl, amelyről az alkalmazás tud, a beállító szkriptből és a helyi másolataidból.', + listHintPrinter: 'Olvasd be a nyomtatót, hogy hozzáadd, amit tárol.', + originMissing: 'A beállító szkriptben, nincs a nyomtatón', + originAbsent: 'Nincs a nyomtatón', + originOnPrinter: 'A nyomtatón', + originPrinterOnly: 'Csak a nyomtatón', + deleteLocalCopyHint: 'A helyi másolat itt marad.', + deleteNoCopyHint: 'Semmi itt nem tart másolatot. Egy gyári objektum visszatér a firmware újratöltésével. Egy feltöltés nem tér vissza.', + firmwareObject: 'A nyomtató megtartja a saját firmware-objektumait, és nem engedi el őket.', }, identity: { printerName: 'Nyomtató neve', diff --git a/src/locales/it.ts b/src/locales/it.ts index 5e58dc1c..345df0f9 100644 --- a/src/locales/it.ts +++ b/src/locales/it.ts @@ -698,8 +698,7 @@ const it = { fontLinksOverLimitFmt: "Più di 5 collegamenti per: {bases}. La stampante ignora silenziosamente l'eccesso.", }, fonts: { - uploadHeading: 'Caricato dallo script di configurazione', - uploadHint: 'Scegli quali font caricati lo script di configurazione invia alla stampante.', + uploadHint: "Scegli un file font che lo script di configurazione invia. Va anche nella cache locale, così la tela può mostrarne l'anteprima.", noFonts: 'Nessun font caricato.', uploadToggle: 'Invia alla configurazione', missingBytes: 'Font mancante. Caricalo o rimuovi la voce.', @@ -723,8 +722,7 @@ const it = { fontCacheTypeInternal: 'Interno (font asiatici)', }, objects: { - uploadHeading: 'Caricato dallo script di configurazione', - uploadHint: "Scegli quali grafiche memorizzate lo script di configurazione carica una sola volta. Imposta la consegna dell'immagine su «Una volta nello script di configurazione» così i lavori la richiamano soltanto.", + uploadHint: 'Scegli un file immagine che lo script di configurazione carica una sola volta. Imposta una consegna immagine su «Una volta nello script di configurazione» così i lavori la richiamano soltanto.', noGraphics: "Nessuna grafica memorizzata. Caricane una qui oppure attiva l'archiviazione stampante su un'immagine.", uploadToggle: 'Invia alla configurazione', fromProfile: 'Conservata in questo profilo stampante', @@ -753,11 +751,8 @@ const it = { cacheDeleteUnusedConfirmFmt: 'Eliminare {n} immagini che non usa né questo documento né la sua cronologia di annullamento? I design salvati in precedenza che le usano le perderanno.', cacheDeleteHistoryOne: "Questo elimina anche l'unico passaggio della cronologia di annullamento che la usa.", cacheDeleteHistoryManyFmt: 'Questo elimina anche {n} passaggi della cronologia di annullamento che la usano.', - printerHeading: 'Sulla stampante', - printerHint: 'Quello che la stampante segnala dalla sua memoria. Leggilo per confrontarlo con lo script di configurazione.', readPrinter: 'Leggi stampante', printerNotRead: 'Non ancora letto.', - printerEmpty: 'La stampante non segnala oggetti di questo tipo.', printerFreeFmt: '{device}: {kb} KB liberi', objectSizeFmt: '{kb} KB', showObject: 'Mostra', @@ -767,6 +762,16 @@ const it = { deleteGraphicConfirmFmt: 'Eliminare {path} dalla stampante? Le etichette che lo richiamano vengono stampate senza di esso.', deleteFontConfirmFmt: 'Eliminare {path} dalla stampante? Le etichette che lo usano passano a un altro font.', setupReuploadHint: 'Lo script di configurazione lo elenca e lo carica di nuovo alla successiva esecuzione.', + listHeading: 'Archiviazione della stampante', + listHint: "Ogni file di questo tipo che l'app conosce, dallo script di configurazione e dalle tue copie locali.", + listHintPrinter: 'Leggi la stampante per aggiungere ciò che detiene.', + originMissing: 'Nello script di configurazione, non sulla stampante', + originAbsent: 'Non sulla stampante', + originOnPrinter: 'Sulla stampante', + originPrinterOnly: 'Solo sulla stampante', + deleteLocalCopyHint: 'La copia locale resta qui.', + deleteNoCopyHint: 'Nulla qui detiene una copia. Un oggetto di fabbrica ritorna con un ricaricamento del firmware. Un caricamento non ritorna.', + firmwareObject: 'La stampante mantiene i propri oggetti firmware e non li lascia andare.', }, identity: { printerName: 'Nome stampante', diff --git a/src/locales/ja.ts b/src/locales/ja.ts index 402abc30..a39bde4f 100644 --- a/src/locales/ja.ts +++ b/src/locales/ja.ts @@ -698,8 +698,7 @@ const ja = { fontLinksOverLimitFmt: '{bases} のリンクが5件を超えています。プリンターは超過分を黙って無視します。', }, fonts: { - uploadHeading: 'セットアップスクリプトによるアップロード', - uploadHint: 'セットアップスクリプトがプリンターに送信する、アップロード済みフォントを選択します。', + uploadHint: 'セットアップスクリプトが送信するフォントファイルを選択します。ローカルキャッシュにも保存されるため、キャンバスでプレビューできます。', noFonts: 'まだフォントがアップロードされていません。', uploadToggle: 'セットアップ時に送信', missingBytes: 'フォントが見つかりません。アップロードするか項目を削除してください。', @@ -723,8 +722,7 @@ const ja = { fontCacheTypeInternal: '内部(アジア言語フォント)', }, objects: { - uploadHeading: 'セットアップスクリプトによるアップロード', - uploadHint: 'セットアップスクリプトが一度だけアップロードする保存済みグラフィックを選択します。画像の配信を「セットアップスクリプトで一度だけ」に設定すると、印刷ジョブは呼び出すだけになります。', + uploadHint: 'セットアップスクリプトが一度だけアップロードする画像ファイルを選択します。画像の配信を「セットアップスクリプトで一度だけ」に設定すると、ジョブは呼び出すだけになります。', noGraphics: '保存済みグラフィックはまだありません。ここからアップロードするか、画像のプリンター記憶を有効にしてください。', uploadToggle: 'セットアップ時に送信', fromProfile: 'このプリンタープロファイルに保存されます', @@ -753,11 +751,8 @@ const ja = { cacheDeleteUnusedConfirmFmt: 'このドキュメントにも元に戻す履歴にも使われていない画像を{n}件削除しますか? それらを使用している以前保存したデザインは画像を失います。', cacheDeleteHistoryOne: 'これにより、それを使用する元に戻す履歴内の唯一の操作も削除されます。', cacheDeleteHistoryManyFmt: 'これにより、それを使用する元に戻す履歴内の操作も{n}件削除されます。', - printerHeading: 'プリンター上', - printerHint: 'プリンターがメモリから報告する内容です。セットアップスクリプトと比較するには読み取ってください。', readPrinter: 'プリンターを読み取る', printerNotRead: 'まだ読み取っていません。', - printerEmpty: 'プリンターはこの種類のオブジェクトを報告していません。', printerFreeFmt: '{device}: {kb} KB 空き', objectSizeFmt: '{kb} KB', showObject: '表示', @@ -767,6 +762,16 @@ const ja = { deleteGraphicConfirmFmt: '{path}をプリンターから削除しますか? それを呼び出すラベルはそれなしで印刷されます。', deleteFontConfirmFmt: '{path}をプリンターから削除しますか? それを使用するラベルは別のフォントに切り替わります。', setupReuploadHint: 'セットアップスクリプトがそれを一覧に含め、次回の実行時に再度アップロードします。', + listHeading: 'プリンターの保存領域', + listHint: 'アプリが把握しているこの種類のすべてのファイルで、セットアップスクリプトとローカルのコピーからのものです。', + listHintPrinter: 'プリンターが保持しているものを追加するには、プリンターを読み取ってください。', + originMissing: 'セットアップスクリプトにありますが、プリンターにはありません', + originAbsent: 'プリンターにありません', + originOnPrinter: 'プリンターにあります', + originPrinterOnly: 'プリンターのみにあります', + deleteLocalCopyHint: 'ローカルのコピーはここに残ります。', + deleteNoCopyHint: 'ここにはコピーがありません。工場出荷時のオブジェクトはファームウェアの再読み込みで復元されます。アップロードしたものは復元されません。', + firmwareObject: 'プリンターは自身のファームウェアオブジェクトを保持し、手放しません。', }, identity: { printerName: 'プリンター名', diff --git a/src/locales/ko.ts b/src/locales/ko.ts index 5e4c0add..6fe7744c 100644 --- a/src/locales/ko.ts +++ b/src/locales/ko.ts @@ -698,8 +698,7 @@ const ko = { fontLinksOverLimitFmt: '{bases}에 대한 링크가 5개를 초과합니다. 프린터는 초과분을 조용히 무시합니다.', }, fonts: { - uploadHeading: '설정 스크립트로 업로드됨', - uploadHint: '설정 스크립트가 프린터로 보낼 업로드된 글꼴을 선택하세요.', + uploadHint: '설정 스크립트가 보낼 글꼴 파일을 선택하세요. 로컬 캐시에도 저장되어 캔버스에서 미리 볼 수 있습니다.', noFonts: '아직 업로드된 글꼴이 없습니다.', uploadToggle: '설정 시 전송', missingBytes: '글꼴 없음. 업로드하거나 항목을 제거하세요.', @@ -723,8 +722,7 @@ const ko = { fontCacheTypeInternal: '내부 (아시아 글꼴)', }, objects: { - uploadHeading: '설정 스크립트로 업로드됨', - uploadHint: '설정 스크립트가 한 번만 업로드할 저장된 그래픽을 선택하세요. 이미지의 전달을 ‘설정 스크립트에 한 번’으로 설정하면 인쇄 작업은 호출만 합니다.', + uploadHint: "설정 스크립트가 한 번만 업로드할 이미지 파일을 선택하세요. 이미지의 전달을 '설정 스크립트에 한 번'으로 설정하면 인쇄 작업은 호출만 합니다.", noGraphics: '아직 저장된 그래픽이 없습니다. 여기에서 하나를 업로드하거나 이미지의 프린터 저장소를 활성화하세요.', uploadToggle: '설정 시 전송', fromProfile: '이 프린터 프로필에 보관됨', @@ -753,11 +751,8 @@ const ko = { cacheDeleteUnusedConfirmFmt: '이 문서에서도, 실행 취소 기록에서도 사용하지 않는 이미지 {n}개를 삭제할까요? 이를 사용하는 이전에 저장한 디자인은 이미지를 잃게 됩니다.', cacheDeleteHistoryOne: '이렇게 하면 이를 사용하는 실행 취소 기록의 하나뿐인 단계도 함께 삭제됩니다.', cacheDeleteHistoryManyFmt: '이렇게 하면 이를 사용하는 실행 취소 기록의 단계 {n}개도 함께 삭제됩니다.', - printerHeading: '프린터에', - printerHint: '프린터가 메모리에서 보고하는 내용입니다. 설정 스크립트와 비교하려면 읽어오세요.', readPrinter: '프린터 읽기', printerNotRead: '아직 읽지 않았습니다.', - printerEmpty: '프린터가 이 종류의 객체를 보고하지 않습니다.', printerFreeFmt: '{device}: {kb} KB 사용 가능', objectSizeFmt: '{kb} KB', showObject: '표시', @@ -767,6 +762,16 @@ const ko = { deleteGraphicConfirmFmt: '{path}를 프린터에서 삭제할까요? 이를 호출하는 레이블은 이것 없이 인쇄됩니다.', deleteFontConfirmFmt: '{path}를 프린터에서 삭제할까요? 이를 사용하는 레이블은 다른 글꼴로 대체됩니다.', setupReuploadHint: '설정 스크립트가 이를 목록에 포함하고 다음 실행 시 다시 업로드합니다.', + listHeading: '프린터 저장소', + listHint: '앱이 알고 있는 이 종류의 모든 파일로, 설정 스크립트와 로컬 복사본에서 가져온 것입니다.', + listHintPrinter: '프린터가 가지고 있는 것을 추가하려면 프린터를 읽어오세요.', + originMissing: '설정 스크립트에는 있지만 프린터에는 없음', + originAbsent: '프린터에 없음', + originOnPrinter: '프린터에 있음', + originPrinterOnly: '프린터에만 있음', + deleteLocalCopyHint: '로컬 복사본은 여기에 남습니다.', + deleteNoCopyHint: '여기에는 복사본이 없습니다. 출고 시 기본 객체는 펌웨어를 다시 불러오면 돌아옵니다. 업로드한 것은 돌아오지 않습니다.', + firmwareObject: '프린터는 자체 펌웨어 객체를 보유하며 이를 내놓지 않습니다.', }, identity: { printerName: '프린터 이름', diff --git a/src/locales/lt.ts b/src/locales/lt.ts index 13a6587a..f1a430ba 100644 --- a/src/locales/lt.ts +++ b/src/locales/lt.ts @@ -698,8 +698,7 @@ const lt = { fontLinksOverLimitFmt: 'Daugiau nei 5 nuorodos: {bases}. Spausdintuvas tyliai ignoruoja perteklių.', }, fonts: { - uploadHeading: 'Įkelta sąrankos scenarijumi', - uploadHint: 'Pasirinkite, kuriuos įkeltus šriftus sąrankos scenarijus siunčia į spausdintuvą.', + uploadHint: 'Pasirinkite šrifto failą, kurį nusiųs sąrankos scenarijus. Jis taip pat patenka į vietinį podėlį, kad drobė galėtų jį peržiūrėti.', noFonts: 'Šriftų dar neįkelta.', uploadToggle: 'Siųsti sąrankoje', missingBytes: 'Trūksta šrifto. Įkelkite jį arba pašalinkite įrašą.', @@ -723,8 +722,7 @@ const lt = { fontCacheTypeInternal: 'Vidinis (Azijos šriftai)', }, objects: { - uploadHeading: 'Įkelta sąrankos scenarijumi', - uploadHint: 'Pasirinkite, kurią įrašytą grafiką sąrankos scenarijus įkelia vieną kartą. Nustatykite paveikslėlio pristatymą į „Vieną kartą sąrankos scenarijuje“, kad užduotys jį tik iškviestų.', + uploadHint: 'Pasirinkite paveikslėlio failą, kurį sąrankos scenarijus įkels vieną kartą. Nustatykite paveikslėlio pristatymą į „Vieną kartą sąrankos scenarijuje“, kad užduotys jį tik iškviestų.', noGraphics: 'Įrašytos grafikos dar nėra. Įkelkite čia vieną arba įjunkite paveikslėlio spausdintuvo saugyklą.', uploadToggle: 'Siųsti sąrankoje', fromProfile: 'Saugoma šiame spausdintuvo profilyje', @@ -753,11 +751,8 @@ const lt = { cacheDeleteUnusedConfirmFmt: 'Ištrinti {n} paveikslėlius, kurių nenaudoja nei šis dokumentas, nei jo atšaukimo istorija? Anksčiau išsaugoti dizainai, kurie juos naudoja, jų neteks.', cacheDeleteHistoryOne: 'Tai taip pat pašalins vienintelį žingsnį atšaukimo istorijoje, kuris jį naudoja.', cacheDeleteHistoryManyFmt: 'Tai taip pat pašalins {n} žingsnius atšaukimo istorijoje, kurie jį naudoja.', - printerHeading: 'Spausdintuve', - printerHint: 'Ką spausdintuvas praneša iš savo atminties. Nuskaitykite, kad palygintumėte su sąrankos scenarijumi.', readPrinter: 'Nuskaityti spausdintuvą', printerNotRead: 'Dar nenuskaityta.', - printerEmpty: 'Spausdintuvas nepraneša apie šios rūšies objektus.', printerFreeFmt: '{device}: {kb} KB laisva', objectSizeFmt: '{kb} KB', showObject: 'Rodyti', @@ -767,6 +762,16 @@ const lt = { deleteGraphicConfirmFmt: 'Ištrinti {path} iš spausdintuvo? Etiketės, kurios jį iškviečia, spausdinamos be jo.', deleteFontConfirmFmt: 'Ištrinti {path} iš spausdintuvo? Etiketės, kurios jį naudoja, persijungia į kitą šriftą.', setupReuploadHint: 'Sąrankos scenarijus jį įtraukia į sąrašą ir vėl įkelia kito paleidimo metu.', + listHeading: 'Spausdintuvo saugykla', + listHint: 'Visi šio tipo failai, kuriuos žino programa, iš sąrankos scenarijaus ir iš vietinių kopijų.', + listHintPrinter: 'Nuskaitykite spausdintuvą, kad pridėtumėte tai, ką jis turi.', + originMissing: 'Sąrankos scenarijuje, bet ne spausdintuve', + originAbsent: 'Nėra spausdintuve', + originOnPrinter: 'Spausdintuve', + originPrinterOnly: 'Tik spausdintuve', + deleteLocalCopyHint: 'Vietinė kopija lieka čia.', + deleteNoCopyHint: 'Čia kopijos nėra. Gamyklinis objektas atsistato iš naujo įkėlus programinę aparatinę įrangą. Įkeltas failas neatsistato.', + firmwareObject: 'Spausdintuvas pasilieka savo programinės aparatinės įrangos objektus ir jų neatsisako.', }, identity: { printerName: 'Spausdintuvo pavadinimas', diff --git a/src/locales/lv.ts b/src/locales/lv.ts index 27479847..fc2f023c 100644 --- a/src/locales/lv.ts +++ b/src/locales/lv.ts @@ -698,8 +698,7 @@ const lv = { fontLinksOverLimitFmt: 'Vairāk nekā 5 saites: {bases}. Printeris klusi ignorē pārpalikumu.', }, fonts: { - uploadHeading: 'Augšupielādēts ar iestatīšanas skriptu', - uploadHint: 'Izvēlieties, kurus augšupielādētos fontus iestatīšanas skripts nosūta printerim.', + uploadHint: 'Izvēlieties fonta failu, ko nosūtīs iestatīšanas skripts. Tas nonāk arī lokālajā kešatmiņā, lai audekls varētu to priekšskatīt.', noFonts: 'Vēl nav augšupielādēts neviens fonts.', uploadToggle: 'Sūtīt iestatīšanā', missingBytes: 'Trūkst fonta. Augšupielādējiet to vai noņemiet ierakstu.', @@ -723,8 +722,7 @@ const lv = { fontCacheTypeInternal: 'Iekšējs (Āzijas fonti)', }, objects: { - uploadHeading: 'Augšupielādēts ar iestatīšanas skriptu', - uploadHint: 'Izvēlieties, kuru saglabāto grafiku iestatīšanas skripts augšupielādē vienreiz. Iestatiet attēla piegādi uz „Vienreiz iestatīšanas skriptā“, lai darbi to tikai izsauktu.', + uploadHint: 'Izvēlieties attēla failu, ko iestatīšanas skripts augšupielādēs vienreiz. Iestatiet attēla piegādi uz „Vienreiz iestatīšanas skriptā“, lai darbi to tikai izsauktu.', noGraphics: 'Saglabātas grafikas vēl nav. Augšupielādējiet šeit vienu vai aktivizējiet attēla printera krātuvi.', uploadToggle: 'Sūtīt iestatīšanā', fromProfile: 'Saglabāts šajā printera profilā', @@ -753,11 +751,8 @@ const lv = { cacheDeleteUnusedConfirmFmt: 'Dzēst {n} attēlus, ko neizmanto ne šis dokuments, ne tā atsaukšanas vēsture? Iepriekš saglabāti dizaini, kas tos izmanto, tos zaudēs.', cacheDeleteHistoryOne: 'Tas arī dzēsīs vienīgo soli atsaukšanas vēsturē, kas to izmanto.', cacheDeleteHistoryManyFmt: 'Tas arī dzēsīs {n} soļus atsaukšanas vēsturē, kas to izmanto.', - printerHeading: 'Printerī', - printerHint: 'Ko printeris paziņo no savas atmiņas. Nolasiet to, lai salīdzinātu ar iestatīšanas skriptu.', readPrinter: 'Nolasīt printeri', printerNotRead: 'Vēl nav nolasīts.', - printerEmpty: 'Printeris nepaziņo par šāda veida objektiem.', printerFreeFmt: '{device}: {kb} KB brīvi', objectSizeFmt: '{kb} KB', showObject: 'Rādīt', @@ -767,6 +762,16 @@ const lv = { deleteGraphicConfirmFmt: 'Dzēst {path} no printera? Etiķetes, kas to izsauc, tiek drukātas bez tā.', deleteFontConfirmFmt: 'Dzēst {path} no printera? Etiķetes, kas to izmanto, pārslēdzas uz citu fontu.', setupReuploadHint: 'Iestatīšanas skripts to norāda sarakstā un augšupielādē atkārtoti nākamajā palaišanas reizē.', + listHeading: 'Printera krātuve', + listHint: 'Visi šāda veida faili, ko lietotne zina, no iestatīšanas skripta un no jūsu lokālajām kopijām.', + listHintPrinter: 'Nolasiet printeri, lai pievienotu to, ko tas glabā.', + originMissing: 'Iestatīšanas skriptā, ne printerī', + originAbsent: 'Nav printerī', + originOnPrinter: 'Printerī', + originPrinterOnly: 'Tikai printerī', + deleteLocalCopyHint: 'Lokālā kopija paliek šeit.', + deleteNoCopyHint: 'Šeit kopijas nav. Rūpnīcas objekts atjaunojas, pārlādējot aparātprogrammatūru. Augšupielādēts fails neatjaunojas.', + firmwareObject: 'Printeris patur savus aparātprogrammatūras objektus un no tiem neatsakās.', }, identity: { printerName: 'Printera nosaukums', diff --git a/src/locales/nl.ts b/src/locales/nl.ts index 852efbb9..5f5dd260 100644 --- a/src/locales/nl.ts +++ b/src/locales/nl.ts @@ -698,8 +698,7 @@ const nl = { fontLinksOverLimitFmt: 'Meer dan 5 koppelingen voor: {bases}. Printer negeert overschot stilzwijgend.', }, fonts: { - uploadHeading: 'Geüpload door het installatiescript', - uploadHint: 'Kies welke geüploade lettertypen het installatiescript naar de printer stuurt.', + uploadHint: 'Kies een lettertypebestand dat het installatiescript verstuurt. Het komt ook in de lokale cache terecht, zodat het canvas het kan voorvertonen.', noFonts: 'Nog geen lettertypen geüpload.', uploadToggle: 'Verzenden bij installatie', missingBytes: 'Lettertype ontbreekt. Upload het of verwijder het item.', @@ -723,8 +722,7 @@ const nl = { fontCacheTypeInternal: 'Intern (Aziatische lettertypen)', }, objects: { - uploadHeading: 'Geüpload door het installatiescript', - uploadHint: 'Kies welke opgeslagen afbeeldingen het installatiescript één keer uploadt. Zet de levering van de afbeelding op “Eenmalig in het installatiescript”, zodat taken die alleen nog oproepen.', + uploadHint: 'Kies een afbeeldingsbestand dat het installatiescript één keer uploadt. Zet de levering van een afbeelding op “Eenmalig in het installatiescript”, zodat taken het alleen oproepen.', noGraphics: 'Nog geen opgeslagen afbeeldingen. Upload er hier een of activeer printer-opslag bij een afbeelding.', uploadToggle: 'Verzenden bij installatie', fromProfile: 'Bewaard in dit printerprofiel', @@ -753,11 +751,8 @@ const nl = { cacheDeleteUnusedConfirmFmt: '{n} afbeeldingen verwijderen die noch dit document, noch de geschiedenis van ongedaan maken gebruikt? Eerder opgeslagen ontwerpen die deze gebruiken, raken ze kwijt.', cacheDeleteHistoryOne: 'Dit verwijdert ook de ene stap in de geschiedenis van ongedaan maken die het gebruikt.', cacheDeleteHistoryManyFmt: 'Dit verwijdert ook {n} stappen in de geschiedenis van ongedaan maken die het gebruiken.', - printerHeading: 'Op de printer', - printerHint: 'Wat de printer meldt uit zijn geheugen. Lees het om te vergelijken met het installatiescript.', readPrinter: 'Printer uitlezen', printerNotRead: 'Nog niet uitgelezen.', - printerEmpty: 'De printer meldt geen objecten van dit type.', printerFreeFmt: '{device}: {kb} KB vrij', objectSizeFmt: '{kb} KB', showObject: 'Weergeven', @@ -767,6 +762,16 @@ const nl = { deleteGraphicConfirmFmt: '{path} van de printer verwijderen? Etiketten die het oproepen, drukken zonder het af.', deleteFontConfirmFmt: '{path} van de printer verwijderen? Etiketten die het gebruiken, vallen terug op een ander lettertype.', setupReuploadHint: 'Het installatiescript vermeldt het en uploadt het opnieuw bij de volgende uitvoering.', + listHeading: 'Printeropslag', + listHint: 'Elk bestand van dit type dat de app kent, van het installatiescript en van uw lokale kopieën.', + listHintPrinter: 'Lees de printer uit om toe te voegen wat hij bevat.', + originMissing: 'In het installatiescript, niet op de printer', + originAbsent: 'Niet op de printer', + originOnPrinter: 'Op de printer', + originPrinterOnly: 'Alleen op de printer', + deleteLocalCopyHint: 'De lokale kopie blijft hier.', + deleteNoCopyHint: 'Niets hier bewaart een kopie. Een fabrieksobject komt terug bij een firmware-herlaad. Een upload komt niet terug.', + firmwareObject: 'De printer houdt zijn eigen firmware-objecten vast en geeft ze niet op.', }, identity: { printerName: 'Printernaam', diff --git a/src/locales/no.ts b/src/locales/no.ts index aa378f09..10e5775f 100644 --- a/src/locales/no.ts +++ b/src/locales/no.ts @@ -698,8 +698,7 @@ const no = { fontLinksOverLimitFmt: 'Mer enn 5 lenker for: {bases}. Skriveren ignorerer overskudd stille.', }, fonts: { - uploadHeading: 'Lastet opp av oppsettsskriptet', - uploadHint: 'Velg hvilke opplastede skrifter oppsettsskriptet sender til skriveren.', + uploadHint: 'Velg en skriftfil som oppsettsskriptet skal sende. Den legges også i den lokale bufferen, slik at lerretet kan forhåndsvise den.', noFonts: 'Ingen skrifter er lastet opp ennå.', uploadToggle: 'Send ved oppsett', missingBytes: 'Skrift mangler. Last opp eller fjern oppføringen.', @@ -723,8 +722,7 @@ const no = { fontCacheTypeInternal: 'Intern (asiatiske skrifter)', }, objects: { - uploadHeading: 'Lastet opp av oppsettsskriptet', - uploadHint: 'Velg hvilken lagret grafikk oppsettsskriptet laster opp én gang. Sett bildets levering til «Én gang i oppsettsskriptet», slik at jobbene bare henter den frem.', + uploadHint: 'Velg en bildefil som oppsettsskriptet skal laste opp én gang. Sett bildets levering til «Én gang i oppsettsskriptet», slik at jobbene bare henter den frem.', noGraphics: 'Ingen lagret grafikk ennå. Last opp en her, eller aktiver skriverlagring på et bilde.', uploadToggle: 'Send ved oppsett', fromProfile: 'Beholdes i denne skriverprofilen', @@ -753,11 +751,8 @@ const no = { cacheDeleteUnusedConfirmFmt: 'Slette {n} bilder som verken dette dokumentet eller angre-historikken bruker? Design du har lagret tidligere og som bruker dem, mister dem.', cacheDeleteHistoryOne: 'Dette fjerner også det ene trinnet i angre-historikken som bruker det.', cacheDeleteHistoryManyFmt: 'Dette fjerner også {n} trinn i angre-historikken som bruker det.', - printerHeading: 'På skriveren', - printerHint: 'Hva skriveren rapporterer fra minnet sitt. Les det for å sammenligne med oppsettsskriptet.', readPrinter: 'Les skriver', printerNotRead: 'Ikke lest ennå.', - printerEmpty: 'Skriveren rapporterer ingen objekter av denne typen.', printerFreeFmt: '{device}: {kb} KB ledig', objectSizeFmt: '{kb} KB', showObject: 'Vis', @@ -767,6 +762,16 @@ const no = { deleteGraphicConfirmFmt: 'Slette {path} fra skriveren? Etiketter som henter det frem, skriver ut uten det.', deleteFontConfirmFmt: 'Slette {path} fra skriveren? Etiketter som bruker den, faller tilbake til en annen skrift.', setupReuploadHint: 'Oppsettsskriptet lister den opp og laster den opp igjen ved neste kjøring.', + listHeading: 'Skriverlagring', + listHint: 'Alle filer av denne typen appen vet om, fra oppsettsskriptet og fra dine lokale kopier.', + listHintPrinter: 'Les skriveren for å legge til det den har.', + originMissing: 'I oppsettsskriptet, ikke på skriveren', + originAbsent: 'Ikke på skriveren', + originOnPrinter: 'På skriveren', + originPrinterOnly: 'Bare på skriveren', + deleteLocalCopyHint: 'Den lokale kopien blir liggende her.', + deleteNoCopyHint: 'Ingenting her har en kopi. Et fabrikkobjekt kommer tilbake ved en ny opplasting av fastvare. En opplasting kommer ikke tilbake.', + firmwareObject: 'Skriveren holder på sine egne fastvareobjekter og gir dem ikke fra seg.', }, identity: { printerName: 'Skrivernavn', diff --git a/src/locales/pl.ts b/src/locales/pl.ts index 35ff52c3..ce409988 100644 --- a/src/locales/pl.ts +++ b/src/locales/pl.ts @@ -698,8 +698,7 @@ const pl = { fontLinksOverLimitFmt: 'Więcej niż 5 łączy dla: {bases}. Drukarka po cichu ignoruje nadmiar.', }, fonts: { - uploadHeading: 'Przesłane przez skrypt konfiguracyjny', - uploadHint: 'Wybierz, które przesłane czcionki skrypt konfiguracyjny wyśle do drukarki.', + uploadHint: 'Wybierz plik czcionki, który wysyła skrypt konfiguracyjny. Trafia też do lokalnej pamięci podręcznej, aby płótno mogło go wyświetlić w podglądzie.', noFonts: 'Nie przesłano jeszcze żadnych czcionek.', uploadToggle: 'Wyślij przy konfiguracji', missingBytes: 'Brak czcionki. Prześlij ją lub usuń wpis.', @@ -723,8 +722,7 @@ const pl = { fontCacheTypeInternal: 'Wewnętrzny (czcionki azjatyckie)', }, objects: { - uploadHeading: 'Przesłane przez skrypt konfiguracyjny', - uploadHint: 'Wybierz, które zapisane grafiki skrypt konfiguracyjny wyśle jeden raz. Ustaw dostarczanie obrazu na „Raz w skrypcie konfiguracyjnym”, aby zadania tylko je przywoływały.', + uploadHint: 'Wybierz plik obrazu, który skrypt konfiguracyjny przesyła raz. Ustaw dostarczanie obrazu na „Raz w skrypcie konfiguracyjnym”, aby zadania tylko go przywoływały.', noGraphics: 'Brak zapisanych grafik. Prześlij tutaj jedną lub włącz pamięć drukarki dla obrazu.', uploadToggle: 'Wyślij przy konfiguracji', fromProfile: 'Przechowywane w tym profilu drukarki', @@ -753,11 +751,8 @@ const pl = { cacheDeleteUnusedConfirmFmt: 'Usunąć {n} obrazów, których nie używa ani ten dokument, ani jego historia cofania? Wcześniej zapisane projekty, które ich używają, je utracą.', cacheDeleteHistoryOne: 'To usunie też jedyny krok w historii cofania, który go używa.', cacheDeleteHistoryManyFmt: 'To usunie też {n} kroków w historii cofania, które go używają.', - printerHeading: 'Na drukarce', - printerHint: 'Co drukarka zgłasza z własnej pamięci. Odczytaj, aby porównać ze skryptem konfiguracyjnym.', readPrinter: 'Odczytaj drukarkę', printerNotRead: 'Jeszcze nie odczytano.', - printerEmpty: 'Drukarka nie zgłasza żadnych obiektów tego rodzaju.', printerFreeFmt: '{device}: {kb} KB wolne', objectSizeFmt: '{kb} KB', showObject: 'Pokaż', @@ -767,6 +762,16 @@ const pl = { deleteGraphicConfirmFmt: 'Usunąć {path} z drukarki? Etykiety, które go przywołują, drukują się bez niego.', deleteFontConfirmFmt: 'Usunąć {path} z drukarki? Etykiety, które z niego korzystają, przechodzą na inną czcionkę.', setupReuploadHint: 'Skrypt konfiguracyjny wymienia go na liście i przesyła ponownie przy następnym uruchomieniu.', + listHeading: 'Pamięć drukarki', + listHint: 'Każdy plik tego rodzaju, o którym wie aplikacja, ze skryptu konfiguracyjnego i z lokalnych kopii.', + listHintPrinter: 'Odczytaj drukarkę, aby dodać to, co ma.', + originMissing: 'W skrypcie konfiguracyjnym, nie na drukarce', + originAbsent: 'Nie na drukarce', + originOnPrinter: 'Na drukarce', + originPrinterOnly: 'Tylko na drukarce', + deleteLocalCopyHint: 'Lokalna kopia zostaje tutaj.', + deleteNoCopyHint: 'Nic tutaj nie ma kopii. Obiekt fabryczny wraca po ponownym wczytaniu oprogramowania układowego. Przesłany plik nie wraca.', + firmwareObject: 'Drukarka zatrzymuje własne obiekty oprogramowania układowego i nie oddaje ich.', }, identity: { printerName: 'Nazwa drukarki', diff --git a/src/locales/pt.ts b/src/locales/pt.ts index 00ff0ec1..cd13d7b2 100644 --- a/src/locales/pt.ts +++ b/src/locales/pt.ts @@ -698,8 +698,7 @@ const pt = { fontLinksOverLimitFmt: 'Mais de 5 vínculos para: {bases}. A impressora ignora silenciosamente o excesso.', }, fonts: { - uploadHeading: 'Carregado pelo script de configuração', - uploadHint: 'Escolha quais fontes carregadas o script de configuração envia para a impressora.', + uploadHint: 'Escolha um ficheiro de fonte para o script de configuração enviar. Também vai para a cache local, para que o canvas possa pré-visualizá-lo.', noFonts: 'Nenhuma fonte carregada ainda.', uploadToggle: 'Enviar na configuração', missingBytes: 'Fonte ausente. Envie-a ou remova a entrada.', @@ -723,8 +722,7 @@ const pt = { fontCacheTypeInternal: 'Interno (fontes asiáticas)', }, objects: { - uploadHeading: 'Carregado pelo script de configuração', - uploadHint: 'Escolha quais imagens guardadas o script de configuração carrega uma vez. Defina a entrega da imagem como «Uma vez no script de configuração» para que os trabalhos apenas a chamem.', + uploadHint: 'Escolha um ficheiro de imagem para o script de configuração carregar uma vez. Defina a entrega da imagem como «Uma vez no script de configuração» para que os trabalhos apenas a chamem.', noGraphics: 'Ainda não há imagens guardadas. Carregue uma aqui ou ative o armazenamento da impressora numa imagem.', uploadToggle: 'Enviar na configuração', fromProfile: 'Guardada neste perfil de impressora', @@ -753,11 +751,8 @@ const pt = { cacheDeleteUnusedConfirmFmt: 'Eliminar {n} imagens que nem este documento nem o respetivo histórico de desfazer usam? Os designs guardados anteriormente que as usam vão perdê-las.', cacheDeleteHistoryOne: 'Isto também remove o único passo do histórico de desfazer que a usa.', cacheDeleteHistoryManyFmt: 'Isto também remove {n} passos do histórico de desfazer que a usam.', - printerHeading: 'Na impressora', - printerHint: 'O que a impressora relata a partir da sua memória. Leia para comparar com o script de configuração.', readPrinter: 'Ler impressora', printerNotRead: 'Ainda não lido.', - printerEmpty: 'A impressora não relata objetos deste tipo.', printerFreeFmt: '{device}: {kb} KB livres', objectSizeFmt: '{kb} KB', showObject: 'Mostrar', @@ -767,6 +762,16 @@ const pt = { deleteGraphicConfirmFmt: 'Eliminar {path} da impressora? As etiquetas que o chamam imprimem sem ele.', deleteFontConfirmFmt: 'Eliminar {path} da impressora? As etiquetas que o usam recorrem a outra fonte.', setupReuploadHint: 'O script de configuração lista-o e carrega-o novamente na próxima execução.', + listHeading: 'Armazenamento da impressora', + listHint: 'Todos os ficheiros deste tipo que a aplicação conhece, do script de configuração e das suas cópias locais.', + listHintPrinter: 'Leia a impressora para adicionar o que guarda.', + originMissing: 'No script de configuração, mas não na impressora', + originAbsent: 'Não está na impressora', + originOnPrinter: 'Na impressora', + originPrinterOnly: 'Só na impressora', + deleteLocalCopyHint: 'A cópia local fica aqui.', + deleteNoCopyHint: 'Nada aqui guarda uma cópia. Um objeto de fábrica volta com uma recarga do firmware. Um carregamento não volta.', + firmwareObject: 'A impressora mantém os seus próprios objetos de firmware e não os liberta.', }, identity: { printerName: 'Nome da impressora', diff --git a/src/locales/ro.ts b/src/locales/ro.ts index 39c6c612..cf9d51b8 100644 --- a/src/locales/ro.ts +++ b/src/locales/ro.ts @@ -698,8 +698,7 @@ const ro = { fontLinksOverLimitFmt: 'Mai mult de 5 legături pentru: {bases}. Imprimanta ignoră silențios excesul.', }, fonts: { - uploadHeading: 'Încărcat de scriptul de configurare', - uploadHint: 'Alege ce fonturi încărcate trimite scriptul de configurare către imprimantă.', + uploadHint: 'Alege un fișier font pentru ca scriptul de configurare să îl trimită. Ajunge și în cache-ul local, astfel încât pânza să îl poată previzualiza.', noFonts: 'Niciun font încărcat încă.', uploadToggle: 'Trimite la configurare', missingBytes: 'Font lipsă. Încarcă-l sau elimină intrarea.', @@ -723,8 +722,7 @@ const ro = { fontCacheTypeInternal: 'Intern (fonturi asiatice)', }, objects: { - uploadHeading: 'Încărcat de scriptul de configurare', - uploadHint: 'Alege ce grafice stocate încarcă o singură dată scriptul de configurare. Setează livrarea imaginii la „O dată în scriptul de configurare”, astfel încât lucrările doar să o apeleze.', + uploadHint: 'Alege un fișier imagine pentru ca scriptul de configurare să îl încarce o singură dată. Setează livrarea imaginii la „O dată în scriptul de configurare”, astfel încât lucrările doar să o apeleze.', noGraphics: 'Încă nu există grafice stocate. Încarcă una aici sau activează stocarea imprimantei pentru o imagine.', uploadToggle: 'Trimite la configurare', fromProfile: 'Păstrat în acest profil de imprimantă', @@ -753,11 +751,8 @@ const ro = { cacheDeleteUnusedConfirmFmt: 'Ștergeți {n} imagini pe care nu le folosește nici acest document, nici istoricul lui de anulare? Design-urile salvate anterior care le folosesc le vor pierde.', cacheDeleteHistoryOne: 'Asta va elimina și singurul pas din istoricul de anulare care o folosește.', cacheDeleteHistoryManyFmt: 'Asta va elimina și {n} pași din istoricul de anulare care o folosesc.', - printerHeading: 'Pe imprimantă', - printerHint: 'Ce raportează imprimanta din memoria ei. Citește-o pentru a o compara cu scriptul de configurare.', readPrinter: 'Citește imprimanta', printerNotRead: 'Încă necitit.', - printerEmpty: 'Imprimanta nu raportează obiecte de acest tip.', printerFreeFmt: '{device}: {kb} KB liberi', objectSizeFmt: '{kb} KB', showObject: 'Arată', @@ -767,6 +762,16 @@ const ro = { deleteGraphicConfirmFmt: 'Ștergeți {path} de pe imprimantă? Etichetele care îl apelează se imprimă fără el.', deleteFontConfirmFmt: 'Ștergeți {path} de pe imprimantă? Etichetele care îl folosesc trec la un alt font.', setupReuploadHint: 'Scriptul de configurare îl listează și îl încarcă din nou la următoarea rulare.', + listHeading: 'Stocare imprimantă', + listHint: 'Toate fișierele de acest tip pe care aplicația le cunoaște, din scriptul de configurare și din copiile tale locale.', + listHintPrinter: 'Citește imprimanta pentru a adăuga ce reține.', + originMissing: 'În scriptul de configurare, dar nu pe imprimantă', + originAbsent: 'Nu este pe imprimantă', + originOnPrinter: 'Pe imprimantă', + originPrinterOnly: 'Doar pe imprimantă', + deleteLocalCopyHint: 'Copia locală rămâne aici.', + deleteNoCopyHint: 'Nimic de aici nu reține o copie. Un obiect din fabrică revine cu o reîncărcare a firmware-ului. O încărcare nu revine.', + firmwareObject: 'Imprimanta își păstrează propriile obiecte de firmware și nu renunță la ele.', }, identity: { printerName: 'Numele imprimantei', diff --git a/src/locales/sk.ts b/src/locales/sk.ts index 7d2cd85b..c03b9afb 100644 --- a/src/locales/sk.ts +++ b/src/locales/sk.ts @@ -698,8 +698,7 @@ const sk = { fontLinksOverLimitFmt: 'Viac ako 5 odkazov pre: {bases}. Tlačiareň ticho ignoruje pretečenie.', }, fonts: { - uploadHeading: 'Nahrané inštalačným skriptom', - uploadHint: 'Vyberte, ktoré nahrané písma odošle inštalačný skript do tlačiarne.', + uploadHint: 'Vyberte súbor písma, ktorý inštalačný skript odošle. Uloží sa aj do lokálnej vyrovnávacej pamäte, aby ho plátno mohlo zobraziť v náhľade.', noFonts: 'Zatiaľ neboli nahrané žiadne písma.', uploadToggle: 'Odoslať pri nastavení', missingBytes: 'Písmo chýba. Nahrajte ho alebo odstráňte záznam.', @@ -723,8 +722,7 @@ const sk = { fontCacheTypeInternal: 'Interný (ázijské písma)', }, objects: { - uploadHeading: 'Nahrané inštalačným skriptom', - uploadHint: 'Vyberte, ktorú uloženú grafiku inštalačný skript nahrá raz. Nastavte doručenie obrázka na „Raz v inštalačnom skripte“, aby ho úlohy iba vyvolávali.', + uploadHint: 'Vyberte obrázkový súbor, ktorý inštalačný skript nahraje raz. Nastavte doručenie obrázka na „Raz v inštalačnom skripte“, aby ho úlohy iba vyvolávali.', noGraphics: 'Zatiaľ nie je uložená žiadna grafika. Nahrajte sem nejakú alebo aktivujte úložisko tlačiarne pri obrázku.', uploadToggle: 'Odoslať pri nastavení', fromProfile: 'Uložené v tomto profile tlačiarne', @@ -753,11 +751,8 @@ const sk = { cacheDeleteUnusedConfirmFmt: 'Odstrániť {n} obrázkov, ktoré nepoužíva tento dokument ani jeho história krokov späť? Skôr uložené návrhy, ktoré ich používajú, o ne prídu.', cacheDeleteHistoryOne: 'Tým sa zároveň odstráni v histórii krokov späť aj jediný krok, ktorý ho používa.', cacheDeleteHistoryManyFmt: 'Tým sa zároveň odstráni v histórii krokov späť aj {n} krokov, ktoré ho používajú.', - printerHeading: 'Na tlačiarni', - printerHint: 'Čo tlačiareň hlási zo svojej pamäte. Prečítajte si to a porovnajte s inštalačným skriptom.', readPrinter: 'Načítať tlačiareň', printerNotRead: 'Zatiaľ neprečítané.', - printerEmpty: 'Tlačiareň nehlási žiadne objekty tohto druhu.', printerFreeFmt: '{device}: {kb} KB voľné', objectSizeFmt: '{kb} KB', showObject: 'Zobraziť', @@ -767,6 +762,16 @@ const sk = { deleteGraphicConfirmFmt: 'Odstrániť {path} z tlačiarne? Štítky, ktoré ho vyvolávajú, sa vytlačia bez neho.', deleteFontConfirmFmt: 'Odstrániť {path} z tlačiarne? Štítky, ktoré ho používajú, prejdú na iné písmo.', setupReuploadHint: 'Inštalačný skript ho uvádza v zozname a pri ďalšom spustení ho znova nahrá.', + listHeading: 'Úložisko tlačiarne', + listHint: 'Všetky súbory tohto druhu, o ktorých aplikácia vie, z inštalačného skriptu a z vašich lokálnych kópií.', + listHintPrinter: 'Načítajte tlačiareň, aby ste doplnili to, čo má.', + originMissing: 'V inštalačnom skripte, ale nie na tlačiarni', + originAbsent: 'Nie je na tlačiarni', + originOnPrinter: 'Na tlačiarni', + originPrinterOnly: 'Len na tlačiarni', + deleteLocalCopyHint: 'Lokálna kópia zostane tu.', + deleteNoCopyHint: 'Nič tu neuchováva kópiu. Továrenský objekt sa vráti po opätovnom nahraní firmvéru. Nahraný súbor sa nevráti.', + firmwareObject: 'Tlačiareň si ponecháva vlastné objekty firmvéru a nikdy sa ich nevzdá.', }, identity: { printerName: 'Názov tlačiarne', diff --git a/src/locales/sl.ts b/src/locales/sl.ts index facf0489..7a423a3c 100644 --- a/src/locales/sl.ts +++ b/src/locales/sl.ts @@ -698,8 +698,7 @@ const sl = { fontLinksOverLimitFmt: 'Več kot 5 povezav za: {bases}. Tiskalnik tiho prezre presežek.', }, fonts: { - uploadHeading: 'Naloženo z namestitvenim skriptom', - uploadHint: 'Izberite, katere naložene pisave namestitveni skript pošlje v tiskalnik.', + uploadHint: 'Izberite datoteko pisave, ki jo namestitveni skript pošlje. Gre tudi v lokalni predpomnilnik, da jo lahko platno prikaže v predogledu.', noFonts: 'Pisave še niso naložene.', uploadToggle: 'Pošlji pri namestitvi', missingBytes: 'Pisava manjka. Naložite jo ali odstranite vnos.', @@ -723,8 +722,7 @@ const sl = { fontCacheTypeInternal: 'Notranji (azijske pisave)', }, objects: { - uploadHeading: 'Naloženo z namestitvenim skriptom', - uploadHint: 'Izberite, katere shranjene grafike namestitveni skript naloži enkrat. Nastavite dostavo slike na „Enkrat v namestitvenem skriptu“, da jo opravila samo prikličejo.', + uploadHint: 'Izberite slikovno datoteko, ki jo namestitveni skript naloži enkrat. Nastavite dostavo slike na „Enkrat v namestitvenem skriptu“, da jo opravila samo prikličejo.', noGraphics: 'Shranjenih grafik še ni. Naložite eno sem ali vklopite shrambo tiskalnika za sliko.', uploadToggle: 'Pošlji pri namestitvi', fromProfile: 'Shranjeno v tem profilu tiskalnika', @@ -753,11 +751,8 @@ const sl = { cacheDeleteUnusedConfirmFmt: 'Izbrišem {n} slik, ki jih ne uporablja niti ta dokument niti njegova zgodovina razveljavitev? Prej shranjeni dizajni, ki jih uporabljajo, jih bodo izgubili.', cacheDeleteHistoryOne: 'S tem bo izbrisan tudi edini korak v zgodovini razveljavitev, ki jo uporablja.', cacheDeleteHistoryManyFmt: 'S tem bo izbrisanih tudi {n} korakov v zgodovini razveljavitev, ki jo uporabljajo.', - printerHeading: 'Na tiskalniku', - printerHint: 'Kaj tiskalnik sporoča iz svojega pomnilnika. Preberite ga, da ga primerjate z namestitvenim skriptom.', readPrinter: 'Preberi tiskalnik', printerNotRead: 'Še ni prebrano.', - printerEmpty: 'Tiskalnik ne sporoča nobenih predmetov te vrste.', printerFreeFmt: '{device}: {kb} KB prosto', objectSizeFmt: '{kb} KB', showObject: 'Prikaži', @@ -767,6 +762,16 @@ const sl = { deleteGraphicConfirmFmt: 'Izbrišem {path} iz tiskalnika? Nalepke, ki ga prikličejo, se natisnejo brez njega.', deleteFontConfirmFmt: 'Izbrišem {path} iz tiskalnika? Nalepke, ki jo uporabljajo, preklopijo na drugo pisavo.', setupReuploadHint: 'Namestitveni skript ga navede na seznamu in ga znova naloži ob naslednjem zagonu.', + listHeading: 'Shramba tiskalnika', + listHint: 'Vse datoteke te vrste, ki jih aplikacija pozna, iz namestitvenega skripta in iz vaših lokalnih kopij.', + listHintPrinter: 'Preberite tiskalnik, da dodate, kar hrani.', + originMissing: 'V namestitvenem skriptu, ne pa na tiskalniku', + originAbsent: 'Ni na tiskalniku', + originOnPrinter: 'Na tiskalniku', + originPrinterOnly: 'Samo na tiskalniku', + deleteLocalCopyHint: 'Lokalna kopija ostane tukaj.', + deleteNoCopyHint: 'Nič tukaj ne hrani kopije. Tovarniški predmet se vrne s ponovnim nalaganjem strojne programske opreme. Naložena datoteka se ne vrne.', + firmwareObject: 'Tiskalnik hrani svoje lastne predmete strojne programske opreme in jih ne izpusti.', }, identity: { printerName: 'Ime tiskalnika', diff --git a/src/locales/sr.ts b/src/locales/sr.ts index 1a8cb957..0deafa91 100644 --- a/src/locales/sr.ts +++ b/src/locales/sr.ts @@ -698,8 +698,7 @@ const sr = { fontLinksOverLimitFmt: 'Više od 5 veza za: {bases}. Štampač tiho ignoriše višak.', }, fonts: { - uploadHeading: 'Отпремљено скриптом за подешавање', - uploadHint: 'Изаберите које отпремљене фонтове скрипта за подешавање шаље на штампач.', + uploadHint: 'Изаберите фајл фонта да га скрипта за подешавање пошаље. Иде и у локални кеш, како би платно могло да га прикаже у прегледу.', noFonts: 'Још увек нису отпремљени фонтови.', uploadToggle: 'Пошаљи при подешавању', missingBytes: 'Фонт недостаје. Отпремите га или уклоните унос.', @@ -723,8 +722,7 @@ const sr = { fontCacheTypeInternal: 'Interni (azijski fontovi)', }, objects: { - uploadHeading: 'Отпремљено скриптом за подешавање', - uploadHint: 'Изаберите које сачуване графике скрипта за подешавање отпрема једном. Поставите испоруку слике на „Једном у скрипти за подешавање” како би је послови само позивали.', + uploadHint: 'Изаберите фајл слике да га скрипта за подешавање отпреми једном. Поставите испоруку слике на „Једном у скрипти за подешавање” како би је послови само позивали.', noGraphics: 'Још увек нема сачуваних графика. Отпремите једну овде или укључите меморију штампача за слику.', uploadToggle: 'Пошаљи при подешавању', fromProfile: 'Чува се у овом профилу штампача', @@ -753,11 +751,8 @@ const sr = { cacheDeleteUnusedConfirmFmt: 'Обрисати {n} слика које не користи ни овај документ ни његову историју опозивања? Раније сачувани дизајни који их користе изгубиће их.', cacheDeleteHistoryOne: 'Ово ће уклонити и једини корак у историји опозивања који је користи.', cacheDeleteHistoryManyFmt: 'Ово ће уклонити и {n} корака у историји опозивања који је користе.', - printerHeading: 'На штампачу', - printerHint: 'Шта штампач пријављује из своје меморије. Прочитајте то да бисте упоредили са скриптом за подешавање.', readPrinter: 'Прочитај штампач', printerNotRead: 'Још није прочитано.', - printerEmpty: 'Штампач не пријављује објекте ове врсте.', printerFreeFmt: '{device}: {kb} KB slobodno', objectSizeFmt: '{kb} KB', showObject: 'Прикажи', @@ -767,6 +762,16 @@ const sr = { deleteGraphicConfirmFmt: 'Обрисати {path} са штампача? Налепнице које га позивају штампају се без њега.', deleteFontConfirmFmt: 'Обрисати {path} са штампача? Налепнице које га користе прелазе на други фонт.', setupReuploadHint: 'Скрипта за подешавање га наводи на списку и поново га отпрема при следећем покретању.', + listHeading: 'Меморија штампача', + listHint: 'Сви фајлови ове врсте о којима апликација зна, из скрипте за подешавање и из ваших локалних копија.', + listHintPrinter: 'Прочитајте штампач да бисте додали оно што чува.', + originMissing: 'У скрипти за подешавање, али није на штампачу', + originAbsent: 'Није на штампачу', + originOnPrinter: 'На штампачу', + originPrinterOnly: 'Само на штампачу', + deleteLocalCopyHint: 'Локална копија остаје овде.', + deleteNoCopyHint: 'Ништа овде не чува копију. Фабрички објекат се враћа поновним учитавањем фирмвера. Отпремљени фајл се не враћа.', + firmwareObject: 'Штампач чува своје сопствене фирмвер објекте и не одустаје од њих.', }, identity: { printerName: 'Назив штампача', diff --git a/src/locales/sv.ts b/src/locales/sv.ts index 71e30bda..9bf3db80 100644 --- a/src/locales/sv.ts +++ b/src/locales/sv.ts @@ -698,8 +698,7 @@ const sv = { fontLinksOverLimitFmt: 'Mer än 5 länkar för: {bases}. Skrivaren ignorerar överskott tyst.', }, fonts: { - uploadHeading: 'Uppladdat av installationsskriptet', - uploadHint: 'Välj vilka uppladdade teckensnitt installationsskriptet skickar till skrivaren.', + uploadHint: 'Välj en teckensnittsfil som installationsskriptet skickar. Den hamnar även i den lokala cachen, så att arbetsytan kan förhandsvisa den.', noFonts: 'Inga teckensnitt har laddats upp än.', uploadToggle: 'Skicka vid installation', missingBytes: 'Teckensnitt saknas. Ladda upp eller ta bort posten.', @@ -723,8 +722,7 @@ const sv = { fontCacheTypeInternal: 'Intern (asiatiska teckensnitt)', }, objects: { - uploadHeading: 'Uppladdat av installationsskriptet', - uploadHint: 'Välj vilken sparad grafik installationsskriptet laddar upp en gång. Ställ in bildens leverans till ”En gång i installationsskriptet” så att jobben bara hämtar fram den.', + uploadHint: 'Välj en bildfil som installationsskriptet laddar upp en gång. Ställ in bildens leverans till ”En gång i installationsskriptet” så att jobben bara hämtar fram den.', noGraphics: 'Ingen sparad grafik än. Ladda upp en här eller aktivera skrivarlagring för en bild.', uploadToggle: 'Skicka vid installation', fromProfile: 'Sparas i den här skrivarprofilen', @@ -753,11 +751,8 @@ const sv = { cacheDeleteUnusedConfirmFmt: 'Ta bort {n} bilder som varken det här dokumentet eller dess ångra-historik använder? Tidigare sparade designer som använder dem förlorar dem.', cacheDeleteHistoryOne: 'Detta tar också bort det enda steget i ångra-historiken som använder det.', cacheDeleteHistoryManyFmt: 'Detta tar också bort {n} steg i ångra-historiken som använder det.', - printerHeading: 'På skrivaren', - printerHint: 'Vad skrivaren rapporterar från sitt minne. Läs det för att jämföra med installationsskriptet.', readPrinter: 'Läs skrivare', printerNotRead: 'Inte läst än.', - printerEmpty: 'Skrivaren rapporterar inga objekt av den här typen.', printerFreeFmt: '{device}: {kb} KB fritt', objectSizeFmt: '{kb} KB', showObject: 'Visa', @@ -767,6 +762,16 @@ const sv = { deleteGraphicConfirmFmt: 'Ta bort {path} från skrivaren? Etiketter som hämtar fram det skriver ut utan det.', deleteFontConfirmFmt: 'Ta bort {path} från skrivaren? Etiketter som använder det faller tillbaka till ett annat teckensnitt.', setupReuploadHint: 'Installationsskriptet listar det och laddar upp det igen vid nästa körning.', + listHeading: 'Skrivarlagring', + listHint: 'Alla filer av den här typen som appen känner till, från installationsskriptet och från dina lokala kopior.', + listHintPrinter: 'Läs skrivaren för att lägga till det den har.', + originMissing: 'I installationsskriptet, men inte på skrivaren', + originAbsent: 'Inte på skrivaren', + originOnPrinter: 'På skrivaren', + originPrinterOnly: 'Bara på skrivaren', + deleteLocalCopyHint: 'Den lokala kopian finns kvar här.', + deleteNoCopyHint: 'Inget här har en kopia. Ett fabriksobjekt kommer tillbaka med en ny firmwareinläsning. En uppladdning kommer inte tillbaka.', + firmwareObject: 'Skrivaren behåller sina egna firmwareobjekt och gör sig aldrig av med dem.', }, identity: { printerName: 'Skrivarnamn', diff --git a/src/locales/tr.ts b/src/locales/tr.ts index 2ed3ab8d..ca3867ec 100644 --- a/src/locales/tr.ts +++ b/src/locales/tr.ts @@ -698,8 +698,7 @@ const tr = { fontLinksOverLimitFmt: "{bases} için 5'ten fazla bağlantı. Yazıcı taşmayı sessizce yok sayar.", }, fonts: { - uploadHeading: 'Kurulum betiği tarafından yüklendi', - uploadHint: 'Kurulum betiğinin yazıcıya hangi yüklenmiş yazı tiplerini göndereceğini seçin.', + uploadHint: 'Kurulum betiğinin göndereceği bir yazı tipi dosyası seçin. Ayrıca yerel önbelleğe de gider, böylece tuval onu önizleyebilir.', noFonts: 'Henüz yazı tipi yüklenmedi.', uploadToggle: 'Kurulumda gönder', missingBytes: 'Yazı tipi eksik. Yükleyin veya kaydı kaldırın.', @@ -723,8 +722,7 @@ const tr = { fontCacheTypeInternal: 'Dahili (Asya yazı tipleri)', }, objects: { - uploadHeading: 'Kurulum betiği tarafından yüklendi', - uploadHint: 'Kurulum betiğinin hangi kayıtlı grafikleri bir kez yükleyeceğini seçin. Görselin teslimatını “Kurulum betiğinde bir kez” olarak ayarlayın, böylece işler onu yalnızca çağırır.', + uploadHint: 'Kurulum betiğinin bir kez yükleyeceği bir görsel dosyası seçin. Görselin teslimatını “Kurulum betiğinde bir kez” olarak ayarlayın, böylece işler onu yalnızca çağırır.', noGraphics: 'Henüz kayıtlı grafik yok. Buradan bir tane yükleyin veya bir görselin yazıcı depolamasını etkinleştirin.', uploadToggle: 'Kurulumda gönder', fromProfile: 'Bu yazıcı profilinde saklanır', @@ -753,11 +751,8 @@ const tr = { cacheDeleteUnusedConfirmFmt: 'Ne bu belgenin ne de geri alma geçmişinin kullanmadığı {n} görsel silinsin mi? Onları kullanan, daha önce kaydettiğiniz tasarımlar görselleri kaybeder.', cacheDeleteHistoryOne: 'Bu işlem onu kullanan geri alma geçmişindeki tek adımı da siler.', cacheDeleteHistoryManyFmt: 'Bu işlem onu kullanan geri alma geçmişindeki {n} adımı da siler.', - printerHeading: 'Yazıcıda', - printerHint: 'Yazıcının belleğinden bildirdiği şey. Kurulum betiğiyle karşılaştırmak için okuyun.', readPrinter: 'Yazıcıyı oku', printerNotRead: 'Henüz okunmadı.', - printerEmpty: 'Yazıcı bu türde hiçbir nesne bildirmiyor.', printerFreeFmt: '{device}: {kb} KB boş', objectSizeFmt: '{kb} KB', showObject: 'Göster', @@ -767,6 +762,16 @@ const tr = { deleteGraphicConfirmFmt: '{path} yazıcıdan silinsin mi? Onu çağıran etiketler onsuz yazdırılır.', deleteFontConfirmFmt: '{path} yazıcıdan silinsin mi? Onu kullanan etiketler başka bir yazı tipine geçer.', setupReuploadHint: 'Kurulum betiği onu listeler ve bir sonraki çalıştırmasında yeniden yükler.', + listHeading: 'Yazıcı deposu', + listHint: 'Uygulamanın bildiği bu türdeki tüm dosyalar, kurulum betiğinden ve yerel kopyalarınızdan.', + listHintPrinter: 'Tuttuklarını eklemek için yazıcıyı okuyun.', + originMissing: 'Kurulum betiğinde, yazıcıda değil', + originAbsent: 'Yazıcıda değil', + originOnPrinter: 'Yazıcıda', + originPrinterOnly: 'Yalnızca yazıcıda', + deleteLocalCopyHint: 'Yerel kopya burada kalır.', + deleteNoCopyHint: 'Burada hiçbir şey kopya tutmuyor. Fabrika nesnesi bir aygıt yazılımı yeniden yüklemesiyle geri gelir. Bir yükleme geri gelmez.', + firmwareObject: 'Yazıcı kendi aygıt yazılımı nesnelerini tutar ve onları bırakmaz.', }, identity: { printerName: 'Yazıcı adı', diff --git a/src/locales/zh-hans.ts b/src/locales/zh-hans.ts index 4d259051..edb2ef45 100644 --- a/src/locales/zh-hans.ts +++ b/src/locales/zh-hans.ts @@ -698,8 +698,7 @@ const zhHans = { fontLinksOverLimitFmt: '{bases} 的链接超过 5 个。打印机将静默忽略超出部分。', }, fonts: { - uploadHeading: '由安装脚本上传', - uploadHint: '选择安装脚本要发送到打印机的已上传字体。', + uploadHint: '选择一个字体文件,由安装脚本发送。它也会进入本地缓存,以便画布预览它。', noFonts: '尚未上传字体。', uploadToggle: '设置时发送', missingBytes: '缺少字体。请上传或删除该条目。', @@ -723,8 +722,7 @@ const zhHans = { fontCacheTypeInternal: '内部(亚洲字体)', }, objects: { - uploadHeading: '由安装脚本上传', - uploadHint: '选择安装脚本一次性上传的已存图形。将图像的交付设为“在安装脚本中一次性”,这样打印作业只需调用它。', + uploadHint: '选择一个图像文件,由安装脚本上传一次。将图像的交付设为“在安装脚本中一次性”,这样打印作业只需调用它。', noGraphics: '尚无已存图形。可在此处上传一个,或为图像启用打印机存储。', uploadToggle: '设置时发送', fromProfile: '保存在此打印机配置文件中', @@ -753,11 +751,8 @@ const zhHans = { cacheDeleteUnusedConfirmFmt: '要删除此文档及其撤销历史记录都未使用的 {n} 张图像吗?之前保存的、使用它们的设计将失去它们。', cacheDeleteHistoryOne: '这还会移除撤销历史记录中使用它的唯一一步。', cacheDeleteHistoryManyFmt: '这还会移除撤销历史记录中使用它的 {n} 步。', - printerHeading: '打印机上', - printerHint: '打印机从其内存中报告的内容。读取它以与安装脚本比较。', readPrinter: '读取打印机', printerNotRead: '尚未读取。', - printerEmpty: '打印机未报告此类对象。', printerFreeFmt: '{device}:{kb} KB 可用', objectSizeFmt: '{kb} KB', showObject: '显示', @@ -767,6 +762,16 @@ const zhHans = { deleteGraphicConfirmFmt: '要从打印机中删除{path}吗?调用它的标签不带它打印。', deleteFontConfirmFmt: '要从打印机中删除{path}吗?使用它的标签回退到其他字体。', setupReuploadHint: '安装脚本将其列出,并在下次运行时重新上传。', + listHeading: '打印机存储', + listHint: '应用知道的所有此类文件,来自安装脚本和您的本地副本。', + listHintPrinter: '读取打印机以添加它保存的内容。', + originMissing: '在安装脚本中,但不在打印机上', + originAbsent: '不在打印机上', + originOnPrinter: '打印机上', + originPrinterOnly: '仅在打印机上', + deleteLocalCopyHint: '本地副本会留在这里。', + deleteNoCopyHint: '这里没有任何副本。出厂对象会随固件重新加载恢复。上传的对象不会恢复。', + firmwareObject: '打印机保留自己的固件对象,不会释放它们。', }, identity: { printerName: '打印机名称', diff --git a/src/locales/zh-hant.ts b/src/locales/zh-hant.ts index ca395e16..d9dde685 100644 --- a/src/locales/zh-hant.ts +++ b/src/locales/zh-hant.ts @@ -698,8 +698,7 @@ const zhHant = { fontLinksOverLimitFmt: '{bases} 的連結超過 5 個。印表機將靜默忽略超出部分。', }, fonts: { - uploadHeading: '由安裝指令稿上傳', - uploadHint: '選擇安裝指令稿要傳送到印表機的已上傳字型。', + uploadHint: '選擇一個字型檔案,交由安裝指令稿傳送。它也會存入本機快取,以便畫布預覽它。', noFonts: '尚未上傳字型。', uploadToggle: '設定時傳送', missingBytes: '缺少字型。請上傳或移除該項目。', @@ -723,8 +722,7 @@ const zhHant = { fontCacheTypeInternal: '內部(亞洲字型)', }, objects: { - uploadHeading: '由安裝指令稿上傳', - uploadHint: '選擇安裝指令稿一次性上傳的已存圖形。將圖片的交付設為「在安裝指令稿中一次」,這樣列印工作只需呼叫它。', + uploadHint: '選擇一個影像檔案,交由安裝指令稿上傳一次。將影像的交付設為「在安裝指令稿中一次」,這樣列印工作只需呼叫它。', noGraphics: '尚無已存圖形。可在此處上傳一個,或為圖像啟用印表機儲存。', uploadToggle: '設定時傳送', fromProfile: '保存在此印表機設定檔中', @@ -753,11 +751,8 @@ const zhHant = { cacheDeleteUnusedConfirmFmt: '要刪除此文件及其復原歷史記錄都未使用的 {n} 張圖片嗎?先前儲存並使用它們的設計將會失去它們。', cacheDeleteHistoryOne: '這還會移除復原歷史記錄中使用它的唯一一步。', cacheDeleteHistoryManyFmt: '這還會移除復原歷史記錄中使用它的 {n} 步。', - printerHeading: '印表機上', - printerHint: '印表機從其記憶體回報的內容。讀取它以便與安裝指令稿比較。', readPrinter: '讀取印表機', printerNotRead: '尚未讀取。', - printerEmpty: '印表機未回報此類物件。', printerFreeFmt: '{device}:{kb} KB 可用', objectSizeFmt: '{kb} KB', showObject: '顯示', @@ -767,6 +762,16 @@ const zhHant = { deleteGraphicConfirmFmt: '要從印表機中刪除{path}嗎?呼叫它的標籤不帶它列印。', deleteFontConfirmFmt: '要從印表機中刪除{path}嗎?使用它的標籤回退到其他字型。', setupReuploadHint: '安裝指令稿將其列出,並在下次執行時重新上傳。', + listHeading: '印表機儲存空間', + listHint: '應用程式知道的所有此類檔案,來自安裝指令稿和您的本機副本。', + listHintPrinter: '讀取印表機以新增它保存的內容。', + originMissing: '在安裝指令稿中,但不在印表機上', + originAbsent: '不在印表機上', + originOnPrinter: '印表機上', + originPrinterOnly: '僅在印表機上', + deleteLocalCopyHint: '本機副本會留在這裡。', + deleteNoCopyHint: '這裡沒有任何副本。出廠物件會隨韌體重新載入恢復。上傳的物件不會恢復。', + firmwareObject: '印表機保留自己的韌體物件,不會釋放它們。', }, identity: { printerName: '印表機名稱', diff --git a/src/store/slices/printerObjectsSlice.ts b/src/store/slices/printerObjectsSlice.ts index 735a4513..04a91ee1 100644 --- a/src/store/slices/printerObjectsSlice.ts +++ b/src/store/slices/printerObjectsSlice.ts @@ -1,5 +1,6 @@ import type { StateCreator } from 'zustand'; import { hostObjectKind, hostObjectPath, type HostDirectory, type HostObject } from '@zplab/core/lib/hostDirectory'; +import { hostListing, listingHolds } from '@zplab/core/lib/storedObjectOrigins'; import type { PrinterOutcome, PrinterQueryFailure } from '../../lib/printerQuery'; import { deletePrinterObject, readPrinterObjectImage, readPrinterObjects } from '../../lib/printerObjects'; import { queryKeyFor, resolveQueryTarget, type QueryTarget } from '../../lib/printTarget'; @@ -60,8 +61,7 @@ export const createPrinterObjectsSlice: StateCreator d.objects.some((o) => hostObjectPath(o) === path)); + const kept = listing.kind === 'ok' && listingHolds(hostListing(listing.value), hostObjectPath(object)); return kept ? { kind: 'ignored' } : undefined; }); },