diff --git a/src/components/Fonts/FontManager.tsx b/src/components/Fonts/FontManager.tsx index f4a6affe..6c0b72a0 100644 --- a/src/components/Fonts/FontManager.tsx +++ b/src/components/Fonts/FontManager.tsx @@ -1,15 +1,103 @@ -import { useRef, useState, useCallback } from 'react'; +import { useRef, useState, useCallback, type FocusEvent } from 'react'; +import { PlusIcon, TrashIcon } from '@heroicons/react/16/solid'; import { getAllFonts, loadFontFile, removeFont } from '../../lib/fontCache'; import { useFontCacheVersion } from '../../hooks/useFontCacheVersion'; +import { useLabelStore } from '../../store/labelStore'; import { useT } from '../../lib/useT'; +import { + DEFAULT_FONT_DRIVE, + ZPL_DRIVE_PREFIXES, + nextFreeAlias, + normalizeAlias, + uploadedFontPath, + upsertCustomFontMapping, +} from '../../lib/customFonts'; import { inputCls, labelCls } from '../Properties/styles'; +import { CollapsibleSection } from '../ui/CollapsibleSection'; +import { ConfirmDialog } from '../ui/ConfirmDialog'; +import type { CustomFontMapping } from '../../types/ObjectType'; + +const PATHS_DATALIST_ID = 'zpl-custom-font-paths'; + +const addBtnCls = + 'flex items-center gap-1.5 px-2 py-1.5 rounded text-xs font-mono border border-dashed border-border text-muted hover:text-text hover:border-border-2 transition-colors'; export function FontManager() { const t = useT(); useFontCacheVersion(); + const customFonts = useLabelStore((s) => s.label.customFonts); + const setLabelConfig = useLabelStore((s) => s.setLabelConfig); const fonts = getAllFonts(); const [adding, setAdding] = useState(false); + const [pendingDelete, setPendingDelete] = useState(null); + + const uploadedNames = new Set(fonts.map((f) => f.name)); + + // Partition customFonts: mappings whose path resolves to an uploaded + // font are reflected inline on that font row; the rest live in the + // printer-resident sub-section. Aliases are namespaced globally per + // label, so duplicate detection runs across both lists. + const aliasByPath = new Map(); + const manualMappings: CustomFontMapping[] = []; + for (const m of customFonts ?? []) { + aliasByPath.set(m.path, m.alias); + const isUploadedPath = + m.path.startsWith(DEFAULT_FONT_DRIVE) && + uploadedNames.has(m.path.slice(DEFAULT_FONT_DRIVE.length)); + if (!isUploadedPath) manualMappings.push(m); + } + + const aliasCounts = new Map(); + for (const m of customFonts ?? []) { + if (m.alias) aliasCounts.set(m.alias, (aliasCounts.get(m.alias) ?? 0) + 1); + } + const isDuplicateAlias = (alias: string) => + !!alias && (aliasCounts.get(alias) ?? 0) > 1; + + const replaceList = (next: CustomFontMapping[]) => { + setLabelConfig({ customFonts: next.length > 0 ? next : undefined }); + }; + + const setAliasForPath = (path: string, rawAlias: string) => { + replaceList( + upsertCustomFontMapping(customFonts, path, normalizeAlias(rawAlias)), + ); + }; + + const updateManualAt = (path: string, patch: Partial) => { + const list = customFonts ?? []; + replaceList( + list.map((m) => + m.path === path + ? { + alias: + patch.alias !== undefined + ? normalizeAlias(patch.alias) + : m.alias, + path: patch.path ?? m.path, + } + : m, + ), + ); + }; + + const removeByPath = (path: string) => { + replaceList((customFonts ?? []).filter((m) => m.path !== path)); + }; + + const addManual = () => { + // Suggest the next free letter from the I-Z 1-9 range so the user + // does not accidentally override a built-in Zebra font letter. They + // can still type any letter manually if they want the override. + const taken = (customFonts ?? []).map((m) => m.alias).filter(Boolean); + replaceList([ + ...(customFonts ?? []), + { alias: nextFreeAlias(taken), path: '' }, + ]); + }; + + const uploadedPaths = fonts.map((f) => uploadedFontPath(f.name)); return (
@@ -22,23 +110,69 @@ export function FontManager() { )}
- {fonts.map((font) => ( - - ))} + {fonts.map((font) => { + const path = uploadedFontPath(font.name); + const alias = aliasByPath.get(path) ?? ''; + return ( + setAliasForPath(path, v)} + onRequestDelete={() => setPendingDelete(font.name)} + /> + ); + })}
{adding ? ( setAdding(false)} /> ) : ( - )} + + + + + + + {ZPL_DRIVE_PREFIXES.map((p) => ( + + + {pendingDelete !== null && ( + { + removeFont(pendingDelete); + setPendingDelete(null); + }} + onCancel={() => setPendingDelete(null)} + /> + )}
); } @@ -47,18 +181,48 @@ export function FontManager() { interface FontEntryProps { name: string; + alias: string; + duplicate: boolean; + onAliasChange: (next: string) => void; + onRequestDelete: () => void; } -function FontEntry({ name }: FontEntryProps) { +function FontEntry({ + name, + alias, + duplicate, + onAliasChange, + onRequestDelete, +}: FontEntryProps) { const t = useT(); return ( -
- F - {name} +
+ + {name} + + onAliasChange(e.target.value)} + /> +
+ ); + })} + +
+ ); +} + // ── AddFontForm ──────────────────────────────────────────────────────────────── interface AddFontFormProps { @@ -83,7 +344,10 @@ function AddFontForm({ onDone }: AddFontFormProps) { const [uploadFailed, setUploadFailed] = useState(false); const handleFileChange = useCallback(async (file: File) => { - const printerName = name.trim() || file.name; + // Default to the source filename uppercased — Zebra printer storage + // conventionally uses uppercase ALL.TTF style identifiers, and a + // freshly-picked file is almost always the user's intended name. + const printerName = name.trim() || file.name.toUpperCase(); setUploading(true); setUploadFailed(false); try { diff --git a/src/components/Properties/PropertiesPanel.tsx b/src/components/Properties/PropertiesPanel.tsx index 8321244d..03fdee00 100644 --- a/src/components/Properties/PropertiesPanel.tsx +++ b/src/components/Properties/PropertiesPanel.tsx @@ -22,11 +22,7 @@ import { CollapsibleSection } from "../ui/CollapsibleSection"; import { AlignButtons } from "./AlignButtons"; import { inputCls, labelCls } from "./styles"; import type { LabelConfig } from "../../types/ObjectType"; - -/** Built-in alphanumeric font IDs the Zebra firmware ships with. Used as - * suggestions for ^CF — the input stays free-text so user-defined ^CW - * aliases (single letters) can still be entered. */ -const ZPL_BUILTIN_FONT_IDS = ['0', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] as const; +import { ZPL_BUILTIN_FONT_IDS } from "../../lib/customFonts"; interface PropertiesPanelProps { /** Imperative handle on the canvas — used for actions that need live render @@ -347,6 +343,30 @@ function LabelConfigPanel({ onUpdate({ widthMm: p.widthMm, heightMm: p.heightMm, dpmm: p.dpmm }); }; + // ^CF / ^A suggestions: built-in font letters plus every alias the + // user has registered via ^CW. Set-based dedup keeps user-overridden + // built-ins from appearing twice. The label on custom aliases shows + // the referenced path so a bare letter is not mistaken for a built-in. + const aliasPaths = new Map(); + for (const m of label.customFonts ?? []) { + if (m.alias) aliasPaths.set(m.alias, m.path); + } + const fontIdOptions = Array.from( + new Set([ + ...ZPL_BUILTIN_FONT_IDS, + ...aliasPaths.keys(), + ]), + ).map((id) => { + const path = aliasPaths.get(id); + // Strip the drive prefix (E:, R:, ...) from the display label; + // the full path stays in the underlying customFonts entry and is + // emitted verbatim to ZPL. + return { + value: id, + label: path ? path.replace(/^[A-Z]:/, '') : undefined, + }; + }); + return (
@@ -806,10 +826,11 @@ function LabelConfigPanel({
- {ZPL_BUILTIN_FONT_IDS.map((id) => ( -
); } + diff --git a/src/lib/customFonts.test.ts b/src/lib/customFonts.test.ts new file mode 100644 index 00000000..64750ca6 --- /dev/null +++ b/src/lib/customFonts.test.ts @@ -0,0 +1,93 @@ +import { describe, it, expect } from "vitest"; +import { + nextFreeAlias, + normalizeAlias, + upsertCustomFontMapping, +} from "./customFonts"; + +describe("normalizeAlias", () => { + it("uppercases letters", () => { + expect(normalizeAlias("m")).toBe("M"); + }); + + it("strips non-alphanumeric characters", () => { + expect(normalizeAlias("!@#")).toBe(""); + expect(normalizeAlias(" m ")).toBe("M"); + }); + + it("keeps only the first valid character", () => { + expect(normalizeAlias("ab")).toBe("A"); + expect(normalizeAlias("#7q")).toBe("7"); + }); + + it("accepts digits", () => { + expect(normalizeAlias("0")).toBe("0"); + }); +}); + +describe("upsertCustomFontMapping", () => { + it("appends a new mapping when path is absent", () => { + expect( + upsertCustomFontMapping( + [{ alias: "A", path: "E:A.TTF" }], + "E:B.TTF", + "B", + ), + ).toEqual([ + { alias: "A", path: "E:A.TTF" }, + { alias: "B", path: "E:B.TTF" }, + ]); + }); + + it("replaces an existing mapping for the same path", () => { + expect( + upsertCustomFontMapping( + [{ alias: "A", path: "E:FOO.TTF" }], + "E:FOO.TTF", + "M", + ), + ).toEqual([{ alias: "M", path: "E:FOO.TTF" }]); + }); + + it("removes the mapping when alias is empty", () => { + expect( + upsertCustomFontMapping( + [ + { alias: "A", path: "E:A.TTF" }, + { alias: "B", path: "E:B.TTF" }, + ], + "E:A.TTF", + "", + ), + ).toEqual([{ alias: "B", path: "E:B.TTF" }]); + }); + + it("treats undefined list as empty", () => { + expect(upsertCustomFontMapping(undefined, "E:X.TTF", "X")).toEqual([ + { alias: "X", path: "E:X.TTF" }, + ]); + }); +}); + +describe("nextFreeAlias", () => { + it("returns I when nothing is taken (first non-built-in)", () => { + expect(nextFreeAlias([])).toBe("I"); + }); + + it("skips taken aliases in the preferred range", () => { + expect(nextFreeAlias(["I", "J", "K"])).toBe("L"); + }); + + it("avoids built-in font letters until the unreserved range is exhausted", () => { + // I-Z + 1-9 = 26 chars; if all are taken the helper falls back to + // the built-in letters. + const taken = "IJKLMNOPQRSTUVWXYZ123456789".split(""); + expect(nextFreeAlias(taken)).toBe("0"); + }); + + it("returns empty when all 36 valid characters are taken", () => { + const all = + "0ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789".split(""); + expect(nextFreeAlias(all)).toBe(""); + }); +}); diff --git a/src/lib/customFonts.ts b/src/lib/customFonts.ts new file mode 100644 index 00000000..07d1833d --- /dev/null +++ b/src/lib/customFonts.ts @@ -0,0 +1,77 @@ +import type { CustomFontMapping } from "../types/ObjectType"; + +/** Characters NOT allowed in a ^CW alias. Used as a strip-pattern on + * user input so a single source of truth feeds both UI surfaces (the + * Custom Fonts editor and the Fonts-tab inline alias). The schema + * regex (`/^[A-Z0-9]$/`) is the inverse and lives next to the schema. */ +export const ALIAS_CHAR_RE = /[^A-Z0-9]/g; + +/** Drive prefix used when surfacing a browser-uploaded font as a + * printer path suggestion. E: (flash) is the most common storage on + * Zebra hardware; users who target a different drive can edit the + * Custom Fonts row directly. */ +export const DEFAULT_FONT_DRIVE = "E:"; + +/** Standard Zebra storage drive prefixes for path suggestions: + * E = flash, R = volatile RAM, A = removable (PCMCIA/CF), B = optional + * on-board flash. The first entry matches `DEFAULT_FONT_DRIVE`. */ +export const ZPL_DRIVE_PREFIXES = ["E:", "R:", "A:", "B:"] as const; + +/** Built-in alphanumeric font IDs the Zebra firmware ships with. + * Used as default-font suggestions and excluded from the auto-pick + * range in `nextFreeAlias` so users do not accidentally override the + * built-ins. */ +export const ZPL_BUILTIN_FONT_IDS = [ + "0", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", +] as const; + +/** The printer-storage path emitted for a browser-uploaded font. */ +export function uploadedFontPath(name: string): string { + return `${DEFAULT_FONT_DRIVE}${name}`; +} + +/** Normalise raw user input into a valid ^CW alias char (or empty + * string if no usable character is present). */ +export function normalizeAlias(raw: string): string { + return raw.toUpperCase().replace(ALIAS_CHAR_RE, "").slice(0, 1); +} + +/** Upsert (or remove) a mapping by path. A non-empty `alias` replaces + * the entry for `path`; an empty `alias` removes it. Order is + * preserved for existing entries; a new entry is appended. */ +export function upsertCustomFontMapping( + list: readonly CustomFontMapping[] | undefined, + path: string, + alias: string, +): CustomFontMapping[] { + const withoutPath = (list ?? []).filter((m) => m.path !== path); + if (!alias) return withoutPath; + return [...withoutPath, { alias, path }]; +} + +const ZPL_BUILTIN_FONT_LETTERS = '0ABCDEFGH'; +const ALIAS_PREFERRED_ORDER = 'IJKLMNOPQRSTUVWXYZ123456789'; + +/** Pick the first alias character that is not already taken. Built-in + * Zebra font letters (0, A-H) are tried only after the unreserved + * range is exhausted; assigning one of them is a deliberate override + * of the built-in font, which we avoid by default. Returns '' if all + * 36 valid alias characters are in use. */ +export function nextFreeAlias(taken: Iterable): string { + const used = new Set(taken); + for (const c of ALIAS_PREFERRED_ORDER) { + if (!used.has(c)) return c; + } + for (const c of ZPL_BUILTIN_FONT_LETTERS) { + if (!used.has(c)) return c; + } + return ''; +} diff --git a/src/lib/zplGenerator.test.ts b/src/lib/zplGenerator.test.ts index 3d87b4fe..545bee05 100644 --- a/src/lib/zplGenerator.test.ts +++ b/src/lib/zplGenerator.test.ts @@ -197,6 +197,118 @@ describe('generateZPL — printer params', () => { expect(zpl).not.toContain('^CFA,'); }); + it('emits one ^CW per custom font mapping', () => { + const zpl = generateZPL( + { + ...BASE_LABEL, + customFonts: [ + { alias: 'M', path: 'E:ARIAL.TTF' }, + { alias: 'B', path: 'E:BOLD.TTF' }, + ], + }, + [], + ); + expect(zpl).toContain('^CWM,E:ARIAL.TTF'); + expect(zpl).toContain('^CWB,E:BOLD.TTF'); + }); + + it('omits ^CW when customFonts is absent or empty', () => { + expect(generateZPL(BASE_LABEL, [])).not.toContain('^CW'); + expect( + generateZPL({ ...BASE_LABEL, customFonts: [] }, []), + ).not.toContain('^CW'); + }); + + it('skips ^CW entries with empty alias or path', () => { + const zpl = generateZPL( + { + ...BASE_LABEL, + customFonts: [ + { alias: '', path: 'E:ORPHAN.TTF' }, + { alias: 'A', path: '' }, + { alias: 'B', path: 'E:OK.TTF' }, + ], + }, + [], + ); + expect(zpl).not.toContain('^CW,'); + expect(zpl).not.toContain('^CWA,\n'); + expect(zpl).toContain('^CWB,E:OK.TTF'); + }); + + it.each(['N', 'R', 'I', 'B'] as const)( + 'rewrites ^A@%s to ^A{alias} when a matching ^CW mapping exists', + (rotation) => { + const text: LabelObject = { + id: 't1', + type: 'text', + x: 10, + y: 10, + rotation: 0, + props: { + content: 'hi', + rotation, + fontHeight: 30, + fontWidth: 0, + printerFontName: 'ARIAL.TTF', + }, + }; + const zpl = generateZPL( + { + ...BASE_LABEL, + customFonts: [{ alias: 'M', path: 'E:ARIAL.TTF' }], + }, + [text], + ); + expect(zpl).toContain('^CWM,E:ARIAL.TTF'); + expect(zpl).toContain(`^AM${rotation},30,0`); + expect(zpl).not.toContain(`^A@${rotation},30,0,E:ARIAL.TTF`); + }, + ); + + it('rewrites ^A@ refs across any drive prefix the path uses', () => { + // The path is whatever the customFonts entry stores. Even if our + // text emit only ever writes E:, an imported label could carry + // R: / A: / B: paths that still need to be matched on re-emit. + const rRef = '^XA^FO0,0^A@N,30,0,R:FOO.TTF^FDhi^FS^XZ'; + const aliasByPath: Record = { 'R:FOO.TTF': 'Q' }; + const rewritten = rRef.replace( + /\^A@([NIRB]),(\d+),(\d+),([A-Z]:[^^\n]+?)(?=\^|\n|$)/g, + (full, rot, h, w, path) => { + const alias = aliasByPath[path]; + return alias ? `^A${alias}${rot},${h},${w}` : full; + }, + ); + expect(rewritten).toContain('^AQN,30,0'); + expect(rewritten).not.toContain('^A@N,30,0,R:FOO.TTF'); + }); + + it('leaves ^A@ verbose when no matching ^CW alias is defined', () => { + const text: LabelObject = { + id: 't1', + type: 'text', + x: 10, + y: 10, + rotation: 0, + props: { + content: 'hi', + rotation: 'N', + fontHeight: 30, + fontWidth: 0, + printerFontName: 'ORPHAN.TTF', + }, + }; + const zpl = generateZPL( + { + ...BASE_LABEL, + customFonts: [{ alias: 'M', path: 'E:OTHER.TTF' }], + }, + [text], + ); + expect(zpl).toContain('^A@N,30,0,E:ORPHAN.TTF'); + expect(zpl).not.toContain('^AMN,30,0'); + }); + it('emits ^PM when mirror is set', () => { expect(generateZPL({ ...BASE_LABEL, mirror: 'Y' }, [])).toContain('^PMY'); expect(generateZPL({ ...BASE_LABEL, mirror: 'N' }, [])).toContain('^PMN'); diff --git a/src/lib/zplGenerator.ts b/src/lib/zplGenerator.ts index ed1b7a83..35781d4b 100644 --- a/src/lib/zplGenerator.ts +++ b/src/lib/zplGenerator.ts @@ -64,6 +64,18 @@ export function generateZPL(label: LabelConfig, objects: LabelObject[]): string if (top !== 0) lines.push(`^LT${top}`); if (label.labelShift) lines.push(`^LS${label.labelShift}`); + // Custom font mappings ──────────────────────────────────────────────────── + // ^CW assigns a single-char alias to a font path on the printer's + // storage, so subsequent ^A{alias} fields can reference it without + // restating the full E:font.TTF path. Skip mappings with an empty + // alias or path — these come from in-progress UI rows and would emit + // malformed ^CW lines that the printer drops silently. + if (label.customFonts?.length) { + for (const f of label.customFonts) { + if (f.alias && f.path) lines.push(`^CW${f.alias},${f.path}`); + } + } + // Default font ──────────────────────────────────────────────────────────── // ^CF f,h,w — positional. Empty slots stay empty (^CFA,,20 sets font A // and width 20, leaving height untouched). Trailing empty slots are @@ -129,5 +141,25 @@ export function generateZPL(label: LabelConfig, objects: LabelObject[]): string lines.push('^XZ'); - return lines.join('\n'); + // Rewrite ^A@...{drive}:NAME.TTF references to ^A{alias} for paths + // that the user has registered via ^CW. The ^CW lines are already + // in the header, so the printer resolves the short form against the + // alias table. Saves bytes and surfaces the user's alias choices in + // the output. The drive prefix pattern is open ([A-Z]:) so the + // rewrite keeps working if text emit ever supports non-E drives. + const aliasByPath = new Map(); + for (const m of label.customFonts ?? []) { + if (m.alias) aliasByPath.set(m.path, m.alias); + } + let output = lines.join('\n'); + if (aliasByPath.size > 0) { + output = output.replace( + /\^A@([NIRB]),(\d+),(\d+),([A-Z]:[^^\n]+?)(?=\^|\n|$)/g, + (full, rot, h, w, path) => { + const alias = aliasByPath.get(path); + return alias ? `^A${alias}${rot},${h},${w}` : full; + }, + ); + } + return output; } diff --git a/src/lib/zplParser.test.ts b/src/lib/zplParser.test.ts index 3665acb9..98fc8a90 100644 --- a/src/lib/zplParser.test.ts +++ b/src/lib/zplParser.test.ts @@ -631,6 +631,47 @@ describe('parseZPL — printer params', () => { expect(labelConfig.defaultFontWidth).toBe(20); }); + it('parses ^CW mapping and resolves ^A{alias} to the printer font', () => { + const { labelConfig, objects } = parseZPL( + '^XA^CWM,E:ARIAL.TTF^FO10,10^AMN,30,0^FDHi^FS^XZ', + 8, + ); + expect(labelConfig.customFonts).toEqual([ + { alias: 'M', path: 'E:ARIAL.TTF' }, + ]); + expect(objects).toHaveLength(1); + expect(props(objects[0]).printerFontName).toBe('ARIAL.TTF'); + }); + + it('ignores invalid ^CW arguments', () => { + const { labelConfig } = parseZPL('^XA^CW,^XZ', 8); + expect(labelConfig.customFonts).toBeUndefined(); + }); + + it('upserts ^CW by alias, keeping the last mapping per alias', () => { + // Two ^CW lines for the same alias: the second should overwrite + // the first in customFonts, matching the runtime fontAliases.set + // last-wins semantics. + const { labelConfig } = parseZPL( + '^XA^CWM,E:OLD.TTF^CWM,E:NEW.TTF^XZ', + 8, + ); + expect(labelConfig.customFonts).toEqual([ + { alias: 'M', path: 'E:NEW.TTF' }, + ]); + }); + + it('keeps separate ^CW mappings that share a path but use different aliases', () => { + const { labelConfig } = parseZPL( + '^XA^CWM,E:FOO.TTF^CWN,E:FOO.TTF^XZ', + 8, + ); + expect(labelConfig.customFonts).toEqual([ + { alias: 'M', path: 'E:FOO.TTF' }, + { alias: 'N', path: 'E:FOO.TTF' }, + ]); + }); + it('parses ~SD instant darkness', () => { expect(parseZPL('~SD07^XA^XZ', 8).labelConfig.instantDarkness).toBe(7); expect(parseZPL('~SD30^XA^XZ', 8).labelConfig.instantDarkness).toBe(30); diff --git a/src/lib/zplParser.ts b/src/lib/zplParser.ts index 19d3392a..a5661a57 100644 --- a/src/lib/zplParser.ts +++ b/src/lib/zplParser.ts @@ -308,6 +308,11 @@ export function parseZPL(zpl: string, dpmm = 8): ParsedZPL { // ^LT label top (vertical offset applied to all field positions) let ltY = 0; + // ^CW alias→path mappings. Single-character aliases that resolve + // ^A{alias} field references back to the original font path. Built + // as the parser walks the header, consulted on each ^A{X} encounter. + const fontAliases = new Map(); + // ^FH state (field hex indicator) let fhActive = false; let fhDelimiter = "_"; @@ -1286,8 +1291,24 @@ export function parseZPL(zpl: string, dpmm = 8): ParsedZPL { } }, + // ^CW {alias},{path} — register an alias for a printer-resident font. + // Subsequent ^A{alias} fields resolve to {path} via the fontAliases + // map. The mapping is also persisted on labelConfig so the generator + // can re-emit it on round-trip. Upsert by alias mirrors the + // Map-set semantics of fontAliases: a later ^CW for the same alias + // replaces the earlier mapping rather than accumulating duplicates. + CW(p) { + const alias = (p[0] ?? "").trim().toUpperCase(); + const path = (p[1] ?? "").trim(); + if (!/^[A-Z0-9]$/.test(alias) || !path) return; + fontAliases.set(alias, path); + const list = (labelConfig.customFonts ?? []).filter( + (m) => m.alias !== alias, + ); + labelConfig.customFonts = [...list, { alias, path }]; + }, + // ── Browser-limit: printer-specific features ──────────────────────────── - CW: mkBrowserLimit("CW"), // font identifier — assigns alias to printer-resident font FL: mkBrowserLimit("FL"), // font link — links fonts on printer storage HT: mkBrowserLimit("HT"), // head test — diagnostic for print head LF: mkBrowserLimit("LF"), // list fonts — queries printer for installed fonts @@ -1378,7 +1399,17 @@ export function parseZPL(zpl: string, dpmm = 8): ParsedZPL { textRot = (rest[0] as TextProps["rotation"]) ?? fwRotation; textH = int(p[1], cfHeight || 30); textW = int(p[2], cfWidth || 0); - partialCmds.add(`^${cmd}`); + // Resolve the font letter via the ^CW alias table if known; the + // path is stored verbatim with its drive prefix (e.g. "E:FOO.TTF"), + // so strip the "X:" segment before handing it to the text object. + const aliasPath = fontAliases.get(cmd[1] ?? ""); + if (aliasPath) { + const colonIdx = aliasPath.indexOf(":"); + pendingPrinterFontName = + (colonIdx >= 0 ? aliasPath.slice(colonIdx + 1) : aliasPath) || undefined; + } else { + partialCmds.add(`^${cmd}`); + } continue; } diff --git a/src/locales/ar.ts b/src/locales/ar.ts index 5cbc3888..83a1df1c 100644 --- a/src/locales/ar.ts +++ b/src/locales/ar.ts @@ -121,6 +121,14 @@ const ar = { defaultFontId: 'الخط', defaultFontHeight: 'الارتفاع (نقاط)', defaultFontWidth: 'العرض (dots)', + customFontsHeading: 'خطوط مخصصة', + customFontsHint: 'أسماء مستعارة للخطوط المخزنة في الطابعة.', + customFontsAlias: 'المعرف', + customFontsAliasHint: 'حرف واحد: A-Z أو 0-9', + customFontsDuplicateAlias: 'معرف مكرر, يُطبَّق التعيين الأخير فقط.', + customFontsPath: 'ملف الخط (مثال: E:ARIAL.TTF)', + customFontsAdd: 'إضافة تعيين', + customFontsRemove: 'إزالة', }, app: { @@ -440,7 +448,13 @@ const ar = { upload: 'رفع', cancel: 'إلغاء', delete: 'حذف', + deleteConfirm: 'إزالة هذا الخط من التصميم؟', uploadError: 'تعذّر تحميل ملف الخط', + aliasHint: 'اسم مستعار ZPL لهذا الملصق (حرف واحد، A-Z أو 0-9)', + aliasAssigned: 'الاسم المستعار ZPL المعيَّن لهذا الملصق', + manualMappingsHeading: 'خطوط الطابعة المقيمة', + manualMappingsHint: 'إشارة إلى خطوط موجودة بالفعل على الطابعة لم يتم رفعها هنا.', + addManualMapping: 'إضافة خط طابعة', }, zebraPrint: { heading: 'إرسال إلى طابعة Zebra', diff --git a/src/locales/bg.ts b/src/locales/bg.ts index 417cce78..c870bed7 100644 --- a/src/locales/bg.ts +++ b/src/locales/bg.ts @@ -121,6 +121,14 @@ const bg = { defaultFontId: 'Шрифт', defaultFontHeight: 'Височина (точки)', defaultFontWidth: 'Ширина (dots)', + customFontsHeading: 'Персонализирани шрифтове', + customFontsHint: 'Псевдоними за шрифтове, съхранени в принтера.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Един знак: A-Z или 0-9', + customFontsDuplicateAlias: 'Дублиран псевдоним, действа само последното съпоставяне.', + customFontsPath: 'Файл с шрифт (напр. E:ARIAL.TTF)', + customFontsAdd: 'Добави съпоставяне', + customFontsRemove: 'Премахни', }, app: { @@ -440,7 +448,13 @@ const bg = { upload: 'Качване', cancel: 'Отказ', delete: 'Изтриване', + deleteConfirm: 'Премахване на този шрифт от дизайна?', uploadError: 'Неуспешно зареждане на шрифтов файл', + aliasHint: 'ZPL псевдоним за този етикет (1 знак, A-Z или 0-9)', + aliasAssigned: 'Зададен ZPL псевдоним за този етикет', + manualMappingsHeading: 'Шрифтове в принтера', + manualMappingsHint: 'Препратка към шрифтове, които вече са в принтера, но не са качени тук.', + addManualMapping: 'Добави шрифт на принтера', }, zebraPrint: { heading: 'Изпрати към принтер Zebra', diff --git a/src/locales/cs.ts b/src/locales/cs.ts index 24fc2fd3..d29c2166 100644 --- a/src/locales/cs.ts +++ b/src/locales/cs.ts @@ -121,6 +121,14 @@ const cs = { defaultFontId: 'Písmo', defaultFontHeight: 'Výška (body)', defaultFontWidth: 'Šířka (dots)', + customFontsHeading: 'Vlastní písma', + customFontsHint: 'Aliasy pro písma uložená v tiskárně.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Jeden znak: A-Z nebo 0-9', + customFontsDuplicateAlias: 'Duplicitní alias, uplatní se pouze poslední mapování.', + customFontsPath: 'Soubor písma (např. E:ARIAL.TTF)', + customFontsAdd: 'Přidat mapování', + customFontsRemove: 'Odebrat', }, app: { @@ -440,7 +448,13 @@ const cs = { upload: 'Nahrát', cancel: 'Zrušit', delete: 'Smazat', + deleteConfirm: 'Odebrat toto písmo z návrhu?', uploadError: 'Soubor písma se nepodařilo načíst', + aliasHint: 'ZPL alias pro tento štítek (1 znak, A-Z nebo 0-9)', + aliasAssigned: 'Přiřazený ZPL alias pro tento štítek', + manualMappingsHeading: 'Písma uložená v tiskárně', + manualMappingsHint: 'Odkaz na písma, která jsou již v tiskárně, ale zde nejsou nahrána.', + addManualMapping: 'Přidat písmo tiskárny', }, zebraPrint: { heading: 'Odeslat na tiskárnu Zebra', diff --git a/src/locales/da.ts b/src/locales/da.ts index 8a1183a5..7948ce93 100644 --- a/src/locales/da.ts +++ b/src/locales/da.ts @@ -121,6 +121,14 @@ const da = { defaultFontId: 'Skrifttype', defaultFontHeight: 'Højde (punkter)', defaultFontWidth: 'Bredde (dots)', + customFontsHeading: 'Tilpassede skrifttyper', + customFontsHint: 'Aliaser til skrifttyper på printeren.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Ét tegn: A-Z eller 0-9', + customFontsDuplicateAlias: 'Dublet alias, kun det sidste mapping gælder.', + customFontsPath: 'Skrifttypefil (f.eks. E:ARIAL.TTF)', + customFontsAdd: 'Tilføj mapping', + customFontsRemove: 'Fjern', }, app: { @@ -440,7 +448,13 @@ const da = { upload: 'Upload', cancel: 'Annuller', delete: 'Slet', + deleteConfirm: 'Fjern denne skrifttype fra designet?', uploadError: 'Skriftfilen kunne ikke indlaeses', + aliasHint: 'ZPL-alias for denne etiket (1 tegn, A-Z eller 0-9)', + aliasAssigned: 'Tildelt ZPL-alias for denne etiket', + manualMappingsHeading: 'Skrifttyper på printeren', + manualMappingsHint: 'Reference til skrifttyper, der allerede er på printeren, men ikke uploadet her.', + addManualMapping: 'Tilføj printerskrifttype', }, zebraPrint: { heading: 'Send til Zebra-printer', diff --git a/src/locales/de.ts b/src/locales/de.ts index 5630b156..8ad08141 100644 --- a/src/locales/de.ts +++ b/src/locales/de.ts @@ -121,6 +121,14 @@ const de = { defaultFontId: 'Schriftart', defaultFontHeight: 'Höhe (Punkte)', defaultFontWidth: 'Breite (dots)', + customFontsHeading: 'Eigene Schriften', + customFontsHint: 'Aliase für Schriften, die auf dem Drucker liegen.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Ein Zeichen: A-Z oder 0-9', + customFontsDuplicateAlias: 'Doppelter Alias, nur das letzte Mapping wird angewendet.', + customFontsPath: 'Schriftdatei (z. B. E:ARIAL.TTF)', + customFontsAdd: 'Mapping hinzufügen', + customFontsRemove: 'Entfernen', }, app: { @@ -461,7 +469,13 @@ const de = { upload: 'Hochladen', cancel: 'Abbrechen', delete: 'Löschen', + deleteConfirm: 'Diese Schrift aus dem Design entfernen?', uploadError: 'Schriftdatei konnte nicht geladen werden', + aliasHint: 'ZPL-Alias für dieses Label (1 Zeichen, A-Z oder 0-9)', + aliasAssigned: 'Zugewiesener ZPL-Alias für dieses Label', + manualMappingsHeading: 'Schriften auf dem Drucker', + manualMappingsHint: 'Schriften referenzieren, die schon auf dem Drucker liegen, aber hier nicht hochgeladen sind.', + addManualMapping: 'Drucker-Schrift hinzufügen', }, } as const; diff --git a/src/locales/el.ts b/src/locales/el.ts index 972f6fd8..f4ad8599 100644 --- a/src/locales/el.ts +++ b/src/locales/el.ts @@ -121,6 +121,14 @@ const el = { defaultFontId: 'Γραμματοσειρά', defaultFontHeight: 'Ύψος (κουκκίδες)', defaultFontWidth: 'Πλάτος (dots)', + customFontsHeading: 'Προσαρμοσμένες γραμματοσειρές', + customFontsHint: 'Ψευδώνυμα για γραμματοσειρές αποθηκευμένες στον εκτυπωτή.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Ένας χαρακτήρας: A-Z ή 0-9', + customFontsDuplicateAlias: 'Διπλό ψευδώνυμο, εφαρμόζεται μόνο η τελευταία αντιστοίχιση.', + customFontsPath: 'Αρχείο γραμματοσειράς (π.χ. E:ARIAL.TTF)', + customFontsAdd: 'Προσθήκη αντιστοίχισης', + customFontsRemove: 'Αφαίρεση', }, app: { @@ -440,7 +448,13 @@ const el = { upload: 'Μεταφόρτωση', cancel: 'Ακύρωση', delete: 'Διαγραφή', + deleteConfirm: 'Αφαίρεση αυτής της γραμματοσειράς από τη σχεδίαση;', uploadError: 'Δεν ήταν δυνατή η φόρτωση του αρχείου γραμματοσειράς', + aliasHint: 'Ψευδώνυμο ZPL για αυτή την ετικέτα (1 χαρακτήρας, A-Z ή 0-9)', + aliasAssigned: 'Εκχωρημένο ψευδώνυμο ZPL για αυτή την ετικέτα', + manualMappingsHeading: 'Γραμματοσειρές στον εκτυπωτή', + manualMappingsHint: 'Αναφορά σε γραμματοσειρές που βρίσκονται ήδη στον εκτυπωτή αλλά δεν έχουν μεταφορτωθεί εδώ.', + addManualMapping: 'Προσθήκη γραμματοσειράς εκτυπωτή', }, zebraPrint: { heading: 'Αποστολή σε εκτυπωτή Zebra', diff --git a/src/locales/en.ts b/src/locales/en.ts index c41c99fd..bfd0e2e6 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -121,6 +121,14 @@ const en = { defaultFontId: 'Font', defaultFontHeight: 'Height (dots)', defaultFontWidth: 'Width (dots)', + customFontsHeading: 'Custom fonts', + customFontsHint: 'Aliases for fonts stored on the printer.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Single character: A-Z or 0-9', + customFontsDuplicateAlias: 'Duplicate alias, only the last mapping takes effect.', + customFontsPath: 'Font file (e.g. E:ARIAL.TTF)', + customFontsAdd: 'Add mapping', + customFontsRemove: 'Remove', }, app: { @@ -461,7 +469,13 @@ const en = { upload: 'Upload', cancel: 'Cancel', delete: 'Delete', + deleteConfirm: 'Remove this font from the design?', uploadError: 'Could not load font file', + aliasHint: 'ZPL alias for this label (1 char, A-Z or 0-9)', + aliasAssigned: 'Assigned ZPL alias for this label', + manualMappingsHeading: 'Printer-resident fonts', + manualMappingsHint: 'Reference fonts already on the printer that are not uploaded here.', + addManualMapping: 'Add printer font', }, } as const; diff --git a/src/locales/es.ts b/src/locales/es.ts index 8058feb2..766e9ce4 100644 --- a/src/locales/es.ts +++ b/src/locales/es.ts @@ -121,6 +121,14 @@ const es = { defaultFontId: 'Fuente', defaultFontHeight: 'Altura (puntos)', defaultFontWidth: 'Ancho (dots)', + customFontsHeading: 'Fuentes personalizadas', + customFontsHint: 'Alias para las fuentes almacenadas en la impresora.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Un solo carácter: A-Z o 0-9', + customFontsDuplicateAlias: 'Alias duplicado, solo el último mapeo tiene efecto.', + customFontsPath: 'Archivo de fuente (p. ej. E:ARIAL.TTF)', + customFontsAdd: 'Añadir mapeo', + customFontsRemove: 'Eliminar', }, app: { @@ -440,7 +448,13 @@ const es = { upload: 'Subir', cancel: 'Cancelar', delete: 'Eliminar', + deleteConfirm: '¿Eliminar esta fuente del diseño?', uploadError: 'No se pudo cargar el archivo de fuente', + aliasHint: 'Alias ZPL para esta etiqueta (1 carácter, A-Z o 0-9)', + aliasAssigned: 'Alias ZPL asignado a esta etiqueta', + manualMappingsHeading: 'Fuentes residentes en la impresora', + manualMappingsHint: 'Referencia a fuentes ya presentes en la impresora pero no cargadas aquí.', + addManualMapping: 'Añadir fuente de impresora', }, zebraPrint: { heading: 'Enviar a impresora Zebra', diff --git a/src/locales/et.ts b/src/locales/et.ts index 8cb64a16..7a8dadc5 100644 --- a/src/locales/et.ts +++ b/src/locales/et.ts @@ -121,6 +121,14 @@ const et = { defaultFontId: 'Font', defaultFontHeight: 'Kõrgus (punktid)', defaultFontWidth: 'Laius (dots)', + customFontsHeading: 'Kohandatud fondid', + customFontsHint: 'Aliased printeris salvestatud fontidele.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Üks märk: A-Z või 0-9', + customFontsDuplicateAlias: 'Korduv alias, kehtib ainult viimane vastendus.', + customFontsPath: 'Fondifail (nt E:ARIAL.TTF)', + customFontsAdd: 'Lisa vastendus', + customFontsRemove: 'Eemalda', }, app: { @@ -440,7 +448,13 @@ const et = { upload: 'Laadi üles', cancel: 'Tühista', delete: 'Kustuta', + deleteConfirm: 'Eemaldada see font kujundusest?', uploadError: 'Fondifaili ei saanud laadida', + aliasHint: 'ZPL alias selle sildi jaoks (1 märk, A-Z või 0-9)', + aliasAssigned: 'Sellele sildile määratud ZPL alias', + manualMappingsHeading: 'Printeri fondid', + manualMappingsHint: 'Viide printeris juba olevatele fontidele, mida pole siia üles laaditud.', + addManualMapping: 'Lisa printeri font', }, zebraPrint: { heading: 'Saada Zebra printerile', diff --git a/src/locales/fa.ts b/src/locales/fa.ts index 68d47b57..7c29ec99 100644 --- a/src/locales/fa.ts +++ b/src/locales/fa.ts @@ -121,6 +121,14 @@ const fa = { defaultFontId: 'قلم', defaultFontHeight: 'ارتفاع (نقطه)', defaultFontWidth: 'عرض (dots)', + customFontsHeading: 'فونت‌های سفارشی', + customFontsHint: 'نام‌های مستعار برای فونت‌های ذخیره‌شده در چاپگر.', + customFontsAlias: 'شناسه', + customFontsAliasHint: 'یک حرف: A-Z یا 0-9', + customFontsDuplicateAlias: 'شناسه تکراری, فقط آخرین نگاشت اعمال می‌شود.', + customFontsPath: 'فایل فونت (مثلاً E:ARIAL.TTF)', + customFontsAdd: 'افزودن نگاشت', + customFontsRemove: 'حذف', }, app: { @@ -440,7 +448,13 @@ const fa = { upload: 'بارگذاری', cancel: 'لغو', delete: 'حذف', + deleteConfirm: 'این فونت از طراحی حذف شود؟', uploadError: 'بارگذاری فایل فونت ممکن نبود', + aliasHint: 'نام مستعار ZPL برای این برچسب (1 حرف، A-Z یا 0-9)', + aliasAssigned: 'نام مستعار ZPL اختصاص‌داده‌شده برای این برچسب', + manualMappingsHeading: 'فونت‌های موجود در چاپگر', + manualMappingsHint: 'ارجاع به فونت‌هایی که از قبل روی چاپگر هستند و اینجا بارگذاری نشده‌اند.', + addManualMapping: 'افزودن فونت چاپگر', }, zebraPrint: { heading: 'ارسال به چاپگر Zebra', diff --git a/src/locales/fi.ts b/src/locales/fi.ts index 10b1f4f8..1abca220 100644 --- a/src/locales/fi.ts +++ b/src/locales/fi.ts @@ -121,6 +121,14 @@ const fi = { defaultFontId: 'Fontti', defaultFontHeight: 'Korkeus (pisteet)', defaultFontWidth: 'Leveys (dots)', + customFontsHeading: 'Mukautetut fontit', + customFontsHint: 'Aliakset tulostimeen tallennetuille fonteille.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Yksi merkki: A-Z tai 0-9', + customFontsDuplicateAlias: 'Toistuva alias, vain viimeinen määritys vaikuttaa.', + customFontsPath: 'Fonttitiedosto (esim. E:ARIAL.TTF)', + customFontsAdd: 'Lisää määritys', + customFontsRemove: 'Poista', }, app: { @@ -440,7 +448,13 @@ const fi = { upload: 'Lataa', cancel: 'Peruuta', delete: 'Poista', + deleteConfirm: 'Poista tämä fontti suunnittelusta?', uploadError: 'Fonttitiedostoa ei voitu ladata', + aliasHint: 'ZPL-alias tälle etiketille (1 merkki, A-Z tai 0-9)', + aliasAssigned: 'Tälle etiketille määritetty ZPL-alias', + manualMappingsHeading: 'Fontit tulostimessa', + manualMappingsHint: 'Viittaa fontteihin, jotka ovat jo tulostimessa mutta joita ei ole ladattu tänne.', + addManualMapping: 'Lisää tulostimen fontti', }, zebraPrint: { heading: 'Lähetä Zebra-tulostimelle', diff --git a/src/locales/fr.ts b/src/locales/fr.ts index a6abdddb..5e0d9299 100644 --- a/src/locales/fr.ts +++ b/src/locales/fr.ts @@ -121,6 +121,14 @@ const fr = { defaultFontId: 'Police', defaultFontHeight: 'Hauteur (points)', defaultFontWidth: 'Largeur (dots)', + customFontsHeading: 'Polices personnalisées', + customFontsHint: 'Alias pour les polices stockées sur l\'imprimante.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Un seul caractère : A-Z ou 0-9', + customFontsDuplicateAlias: 'Alias en double, seul le dernier mappage est appliqué.', + customFontsPath: 'Fichier de police (ex. E:ARIAL.TTF)', + customFontsAdd: 'Ajouter un mappage', + customFontsRemove: 'Supprimer', }, app: { @@ -440,7 +448,13 @@ const fr = { upload: 'Téléverser', cancel: 'Annuler', delete: 'Supprimer', + deleteConfirm: 'Retirer cette police du design ?', uploadError: 'Impossible de charger le fichier de police', + aliasHint: 'Alias ZPL pour cette étiquette (1 caractère, A-Z ou 0-9)', + aliasAssigned: 'Alias ZPL assigné pour cette étiquette', + manualMappingsHeading: 'Polices résidentes', + manualMappingsHint: 'Référencer des polices déjà présentes sur l\'imprimante mais non téléversées ici.', + addManualMapping: 'Ajouter une police d\'imprimante', }, zebraPrint: { heading: 'Envoyer à l’imprimante Zebra', diff --git a/src/locales/he.ts b/src/locales/he.ts index 423d8d3e..b9efb583 100644 --- a/src/locales/he.ts +++ b/src/locales/he.ts @@ -121,6 +121,14 @@ const he = { defaultFontId: 'גופן', defaultFontHeight: 'גובה (נקודות)', defaultFontWidth: 'רוחב (dots)', + customFontsHeading: 'גופנים מותאמים', + customFontsHint: 'כינויים לגופנים השמורים במדפסת.', + customFontsAlias: 'מזהה', + customFontsAliasHint: 'תו אחד: A-Z או 0-9', + customFontsDuplicateAlias: 'כינוי כפול, רק המיפוי האחרון מיושם.', + customFontsPath: 'קובץ גופן (לדוגמה E:ARIAL.TTF)', + customFontsAdd: 'הוסף מיפוי', + customFontsRemove: 'הסר', }, app: { @@ -440,7 +448,13 @@ const he = { upload: 'העלה', cancel: 'ביטול', delete: 'מחק', + deleteConfirm: 'להסיר גופן זה מהעיצוב?', uploadError: 'לא ניתן לטעון את קובץ הגופן', + aliasHint: 'כינוי ZPL לתווית זו (תו אחד, A-Z או 0-9)', + aliasAssigned: 'כינוי ZPL מוקצה לתווית זו', + manualMappingsHeading: 'גופנים השמורים במדפסת', + manualMappingsHint: 'התייחסות לגופנים שכבר נמצאים במדפסת ולא הועלו כאן.', + addManualMapping: 'הוסף גופן מדפסת', }, zebraPrint: { heading: 'שלח למדפסת Zebra', diff --git a/src/locales/hr.ts b/src/locales/hr.ts index 161488aa..0f4d136c 100644 --- a/src/locales/hr.ts +++ b/src/locales/hr.ts @@ -121,6 +121,14 @@ const hr = { defaultFontId: 'Font', defaultFontHeight: 'Visina (točke)', defaultFontWidth: 'Širina (dots)', + customFontsHeading: 'Prilagođeni fontovi', + customFontsHint: 'Aliasi za fontove pohranjene na pisaču.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Jedan znak: A-Z ili 0-9', + customFontsDuplicateAlias: 'Duplikat aliasa, primjenjuje se samo posljednje mapiranje.', + customFontsPath: 'Datoteka fonta (npr. E:ARIAL.TTF)', + customFontsAdd: 'Dodaj mapiranje', + customFontsRemove: 'Ukloni', }, app: { @@ -440,7 +448,13 @@ const hr = { upload: 'Prenesi', cancel: 'Odustani', delete: 'Izbriši', + deleteConfirm: 'Ukloniti ovaj font iz dizajna?', uploadError: 'Datoteka fonta nije mogla biti učitana', + aliasHint: 'ZPL alias za ovu etiketu (1 znak, A-Z ili 0-9)', + aliasAssigned: 'Dodijeljen ZPL alias za ovu etiketu', + manualMappingsHeading: 'Fontovi na pisaču', + manualMappingsHint: 'Referenca na fontove koji se već nalaze na pisaču, ali nisu prenijeti ovdje.', + addManualMapping: 'Dodaj font pisača', }, zebraPrint: { heading: 'Pošalji na Zebra pisač', diff --git a/src/locales/hu.ts b/src/locales/hu.ts index b21d30a4..638d2532 100644 --- a/src/locales/hu.ts +++ b/src/locales/hu.ts @@ -121,6 +121,14 @@ const hu = { defaultFontId: 'Betűtípus', defaultFontHeight: 'Magasság (pontok)', defaultFontWidth: 'Szélesség (dots)', + customFontsHeading: 'Egyéni betűtípusok', + customFontsHint: 'Aliasok a nyomtatón tárolt betűtípusokhoz.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Egy karakter: A-Z vagy 0-9', + customFontsDuplicateAlias: 'Ismétlődő alias, csak az utolsó hozzárendelés érvényes.', + customFontsPath: 'Betűtípusfájl (pl. E:ARIAL.TTF)', + customFontsAdd: 'Hozzárendelés hozzáadása', + customFontsRemove: 'Eltávolítás', }, app: { @@ -440,7 +448,13 @@ const hu = { upload: 'Feltöltés', cancel: 'Mégse', delete: 'Törlés', + deleteConfirm: 'Eltávolítja ezt a betűtípust a tervből?', uploadError: 'A betűtípus-fájl nem tölthető be', + aliasHint: 'ZPL alias ehhez a címkéhez (1 karakter, A-Z vagy 0-9)', + aliasAssigned: 'Hozzárendelt ZPL alias ehhez a címkéhez', + manualMappingsHeading: 'Betűtípusok a nyomtatón', + manualMappingsHint: 'Hivatkozás a nyomtatón már lévő, itt fel nem töltött betűtípusokra.', + addManualMapping: 'Nyomtató betűtípus hozzáadása', }, zebraPrint: { heading: 'Küldés Zebra nyomtatóra', diff --git a/src/locales/it.ts b/src/locales/it.ts index 536f6bfd..cf90ac81 100644 --- a/src/locales/it.ts +++ b/src/locales/it.ts @@ -121,6 +121,14 @@ const it = { defaultFontId: 'Carattere', defaultFontHeight: 'Altezza (punti)', defaultFontWidth: 'Larghezza (dots)', + customFontsHeading: 'Font personalizzati', + customFontsHint: 'Alias per i font memorizzati sulla stampante.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Un solo carattere: A-Z o 0-9', + customFontsDuplicateAlias: 'Alias duplicato — solo l\'ultima mappatura ha effetto.', + customFontsPath: 'File del font (es. E:ARIAL.TTF)', + customFontsAdd: 'Aggiungi mappatura', + customFontsRemove: 'Rimuovi', }, app: { @@ -440,7 +448,13 @@ const it = { upload: 'Carica', cancel: 'Annulla', delete: 'Elimina', + deleteConfirm: 'Rimuovere questo font dal design?', uploadError: 'Impossibile caricare il file del carattere', + aliasHint: 'Alias ZPL per questa etichetta (1 carattere, A-Z o 0-9)', + aliasAssigned: 'Alias ZPL assegnato a questa etichetta', + manualMappingsHeading: 'Font residenti sulla stampante', + manualMappingsHint: 'Riferimento a font già presenti sulla stampante ma non caricati qui.', + addManualMapping: 'Aggiungi font della stampante', }, zebraPrint: { heading: 'Invia a stampante Zebra', diff --git a/src/locales/ja.ts b/src/locales/ja.ts index 0f742b8e..23ec772e 100644 --- a/src/locales/ja.ts +++ b/src/locales/ja.ts @@ -121,6 +121,14 @@ const ja = { defaultFontId: 'フォント', defaultFontHeight: '高さ (ドット)', defaultFontWidth: '幅 (dots)', + customFontsHeading: 'カスタムフォント', + customFontsHint: 'プリンターに保存されたフォントのエイリアス。', + customFontsAlias: 'ID', + customFontsAliasHint: '1 文字: A-Z または 0-9', + customFontsDuplicateAlias: 'エイリアスが重複しています。最後のマッピングのみが適用されます。', + customFontsPath: 'フォントファイル (例: E:ARIAL.TTF)', + customFontsAdd: 'マッピングを追加', + customFontsRemove: '削除', }, app: { @@ -440,7 +448,13 @@ const ja = { upload: 'アップロード', cancel: 'キャンセル', delete: '削除', + deleteConfirm: 'このフォントをデザインから削除しますか?', uploadError: 'フォントファイルを読み込めませんでした', + aliasHint: 'このラベルの ZPL エイリアス (1 文字, A-Z または 0-9)', + aliasAssigned: 'このラベルに割り当てられた ZPL エイリアス', + manualMappingsHeading: 'プリンター内蔵フォント', + manualMappingsHint: 'プリンターに既にあるがここにアップロードされていないフォントを参照します。', + addManualMapping: 'プリンターフォントを追加', }, zebraPrint: { heading: 'Zebra プリンターへ送信', diff --git a/src/locales/ko.ts b/src/locales/ko.ts index 5ed28fc0..4f907395 100644 --- a/src/locales/ko.ts +++ b/src/locales/ko.ts @@ -121,6 +121,14 @@ const ko = { defaultFontId: '글꼴', defaultFontHeight: '높이 (도트)', defaultFontWidth: '너비 (dots)', + customFontsHeading: '사용자 글꼴', + customFontsHint: '프린터에 저장된 글꼴의 별칭입니다.', + customFontsAlias: 'ID', + customFontsAliasHint: '한 글자: A-Z 또는 0-9', + customFontsDuplicateAlias: '중복된 별칭, 마지막 매핑만 적용됩니다.', + customFontsPath: '글꼴 파일 (예: E:ARIAL.TTF)', + customFontsAdd: '매핑 추가', + customFontsRemove: '제거', }, app: { @@ -440,7 +448,13 @@ const ko = { upload: '업로드', cancel: '취소', delete: '삭제', + deleteConfirm: '이 글꼴을 디자인에서 제거하시겠습니까?', uploadError: '글꼴 파일을 불러올 수 없습니다', + aliasHint: '이 라벨의 ZPL 별칭 (1 글자, A-Z 또는 0-9)', + aliasAssigned: '이 라벨에 할당된 ZPL 별칭', + manualMappingsHeading: '프린터 내 글꼴', + manualMappingsHint: '프린터에 이미 있지만 여기에 업로드되지 않은 글꼴을 참조합니다.', + addManualMapping: '프린터 글꼴 추가', }, zebraPrint: { heading: 'Zebra 프린터로 전송', diff --git a/src/locales/lt.ts b/src/locales/lt.ts index daf18a7f..4057e9e5 100644 --- a/src/locales/lt.ts +++ b/src/locales/lt.ts @@ -121,6 +121,14 @@ const lt = { defaultFontId: 'Šriftas', defaultFontHeight: 'Aukštis (taškai)', defaultFontWidth: 'Plotis (dots)', + customFontsHeading: 'Pasirinktiniai šriftai', + customFontsHint: 'Aliasai spausdintuve saugomiems šriftams.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Vienas simbolis: A-Z arba 0-9', + customFontsDuplicateAlias: 'Pasikartojantis alias, taikomas tik paskutinis susiejimas.', + customFontsPath: 'Šrifto failas (pvz., E:ARIAL.TTF)', + customFontsAdd: 'Pridėti susiejimą', + customFontsRemove: 'Pašalinti', }, app: { @@ -440,7 +448,13 @@ const lt = { upload: 'Įkelti', cancel: 'Atšaukti', delete: 'Ištrinti', + deleteConfirm: 'Pašalinti šį šriftą iš dizaino?', uploadError: 'Nepavyko įkelti šrifto failo', + aliasHint: 'ZPL alias šiai etiketei (1 simbolis, A-Z arba 0-9)', + aliasAssigned: 'Šiai etiketei priskirtas ZPL alias', + manualMappingsHeading: 'Spausdintuve esantys šriftai', + manualMappingsHint: 'Nuoroda į spausdintuve jau esančius šriftus, kurie čia neįkelti.', + addManualMapping: 'Pridėti spausdintuvo šriftą', }, zebraPrint: { heading: 'Siųsti į Zebra spausdintuvą', diff --git a/src/locales/lv.ts b/src/locales/lv.ts index 6fe5430a..3fd699d7 100644 --- a/src/locales/lv.ts +++ b/src/locales/lv.ts @@ -121,6 +121,14 @@ const lv = { defaultFontId: 'Fonts', defaultFontHeight: 'Augstums (punkti)', defaultFontWidth: 'Platums (dots)', + customFontsHeading: 'Pielāgotie fonti', + customFontsHint: 'Aliasi printerī saglabātajiem fontiem.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Viena rakstzīme: A-Z vai 0-9', + customFontsDuplicateAlias: 'Dublēts aliass, darbojas tikai pēdējā piesaiste.', + customFontsPath: 'Fonta fails (piem., E:ARIAL.TTF)', + customFontsAdd: 'Pievienot piesaisti', + customFontsRemove: 'Noņemt', }, app: { @@ -440,7 +448,13 @@ const lv = { upload: 'Augšupielādēt', cancel: 'Atcelt', delete: 'Dzēst', + deleteConfirm: 'Vai noņemt šo fontu no dizaina?', uploadError: 'Neizdevās ielādēt fontu failu', + aliasHint: 'ZPL aliass šai etiķetei (1 rakstzīme, A-Z vai 0-9)', + aliasAssigned: 'Šai etiķetei piešķirts ZPL aliass', + manualMappingsHeading: 'Printera fonti', + manualMappingsHint: 'Atsauce uz fontiem, kas jau ir printerī, bet nav augšupielādēti šeit.', + addManualMapping: 'Pievienot printera fontu', }, zebraPrint: { heading: 'Sūtīt uz Zebra printeri', diff --git a/src/locales/nl.ts b/src/locales/nl.ts index 2fcbc9b6..7aa78c1e 100644 --- a/src/locales/nl.ts +++ b/src/locales/nl.ts @@ -121,6 +121,14 @@ const nl = { defaultFontId: 'Lettertype', defaultFontHeight: 'Hoogte (dots)', defaultFontWidth: 'Breedte (dots)', + customFontsHeading: 'Aangepaste lettertypen', + customFontsHint: 'Aliassen voor lettertypen op de printer.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Eén teken: A-Z of 0-9', + customFontsDuplicateAlias: 'Dubbele alias, alleen de laatste mapping wordt toegepast.', + customFontsPath: 'Lettertypebestand (bv. E:ARIAL.TTF)', + customFontsAdd: 'Mapping toevoegen', + customFontsRemove: 'Verwijderen', }, app: { @@ -440,7 +448,13 @@ const nl = { upload: 'Uploaden', cancel: 'Annuleren', delete: 'Verwijderen', + deleteConfirm: 'Dit lettertype uit het ontwerp verwijderen?', uploadError: 'Lettertypebestand kon niet worden geladen', + aliasHint: 'ZPL-alias voor dit label (1 teken, A-Z of 0-9)', + aliasAssigned: 'Toegewezen ZPL-alias voor dit label', + manualMappingsHeading: 'Lettertypen op de printer', + manualMappingsHint: 'Verwijs naar lettertypen die al op de printer staan maar hier niet zijn geüpload.', + addManualMapping: 'Printerlettertype toevoegen', }, zebraPrint: { heading: 'Verzenden naar Zebra-printer', diff --git a/src/locales/no.ts b/src/locales/no.ts index ab822d33..aecfa9dd 100644 --- a/src/locales/no.ts +++ b/src/locales/no.ts @@ -121,6 +121,14 @@ const no = { defaultFontId: 'Skrift', defaultFontHeight: 'Høyde (punkter)', defaultFontWidth: 'Bredde (dots)', + customFontsHeading: 'Egendefinerte skrifter', + customFontsHint: 'Aliaser for skrifter som ligger på skriveren.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Ett tegn: A-Z eller 0-9', + customFontsDuplicateAlias: 'Duplisert alias, kun siste mapping gjelder.', + customFontsPath: 'Skriftfil (f.eks. E:ARIAL.TTF)', + customFontsAdd: 'Legg til mapping', + customFontsRemove: 'Fjern', }, app: { @@ -440,7 +448,13 @@ const no = { upload: 'Last opp', cancel: 'Avbryt', delete: 'Slett', + deleteConfirm: 'Fjern denne skriften fra designet?', uploadError: 'Klarte ikke laste inn skriftfilen', + aliasHint: 'ZPL-alias for denne etiketten (1 tegn, A-Z eller 0-9)', + aliasAssigned: 'Tilordnet ZPL-alias for denne etiketten', + manualMappingsHeading: 'Skrifter på skriveren', + manualMappingsHint: 'Referer til skrifter som allerede ligger på skriveren, men ikke er lastet opp her.', + addManualMapping: 'Legg til skriverskrift', }, zebraPrint: { heading: 'Send til Zebra-skriver', diff --git a/src/locales/pl.ts b/src/locales/pl.ts index e9fca70b..b0f798a0 100644 --- a/src/locales/pl.ts +++ b/src/locales/pl.ts @@ -121,6 +121,14 @@ const pl = { defaultFontId: 'Czcionka', defaultFontHeight: 'Wysokość (punkty)', defaultFontWidth: 'Szerokość (dots)', + customFontsHeading: 'Niestandardowe czcionki', + customFontsHint: 'Aliasy dla czcionek zapisanych w pamięci drukarki.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Jeden znak: A-Z lub 0-9', + customFontsDuplicateAlias: 'Zduplikowany alias, działa tylko ostatnie mapowanie.', + customFontsPath: 'Plik czcionki (np. E:ARIAL.TTF)', + customFontsAdd: 'Dodaj mapowanie', + customFontsRemove: 'Usuń', }, app: { @@ -440,7 +448,13 @@ const pl = { upload: 'Prześlij', cancel: 'Anuluj', delete: 'Usuń', + deleteConfirm: 'Usunąć tę czcionkę z projektu?', uploadError: 'Nie można załadować pliku czcionki', + aliasHint: 'Alias ZPL dla tej etykiety (1 znak, A-Z lub 0-9)', + aliasAssigned: 'Przypisany alias ZPL dla tej etykiety', + manualMappingsHeading: 'Czcionki w pamięci drukarki', + manualMappingsHint: 'Odwołuje się do czcionek już w drukarce, niewgranych tutaj.', + addManualMapping: 'Dodaj czcionkę drukarki', }, zebraPrint: { heading: 'Wyślij do drukarki Zebra', diff --git a/src/locales/pt.ts b/src/locales/pt.ts index 1d269a5d..16b93c62 100644 --- a/src/locales/pt.ts +++ b/src/locales/pt.ts @@ -121,6 +121,14 @@ const pt = { defaultFontId: 'Fonte', defaultFontHeight: 'Altura (pontos)', defaultFontWidth: 'Largura (dots)', + customFontsHeading: 'Fontes personalizadas', + customFontsHint: 'Aliases para fontes armazenadas na impressora.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Um único caractere: A-Z ou 0-9', + customFontsDuplicateAlias: 'Alias duplicado, só o último mapeamento é aplicado.', + customFontsPath: 'Arquivo de fonte (ex. E:ARIAL.TTF)', + customFontsAdd: 'Adicionar mapeamento', + customFontsRemove: 'Remover', }, app: { @@ -440,7 +448,13 @@ const pt = { upload: 'Carregar', cancel: 'Cancelar', delete: 'Excluir', + deleteConfirm: 'Remover esta fonte do design?', uploadError: 'Não foi possível carregar o arquivo de fonte', + aliasHint: 'Alias ZPL para esta etiqueta (1 caractere, A-Z ou 0-9)', + aliasAssigned: 'Alias ZPL atribuído a esta etiqueta', + manualMappingsHeading: 'Fontes residentes na impressora', + manualMappingsHint: 'Referencia fontes já presentes na impressora mas não enviadas aqui.', + addManualMapping: 'Adicionar fonte da impressora', }, zebraPrint: { heading: 'Enviar para impressora Zebra', diff --git a/src/locales/ro.ts b/src/locales/ro.ts index 426fcc85..724edb1d 100644 --- a/src/locales/ro.ts +++ b/src/locales/ro.ts @@ -121,6 +121,14 @@ const ro = { defaultFontId: 'Font', defaultFontHeight: 'Înălțime (puncte)', defaultFontWidth: 'Lățime (dots)', + customFontsHeading: 'Fonturi personalizate', + customFontsHint: 'Aliasuri pentru fonturile stocate pe imprimantă.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Un singur caracter: A-Z sau 0-9', + customFontsDuplicateAlias: 'Alias duplicat, doar ultima mapare are efect.', + customFontsPath: 'Fișier font (ex. E:ARIAL.TTF)', + customFontsAdd: 'Adaugă mapare', + customFontsRemove: 'Elimină', }, app: { @@ -440,7 +448,13 @@ const ro = { upload: 'Încarcă', cancel: 'Anulează', delete: 'Șterge', + deleteConfirm: 'Eliminați acest font din design?', uploadError: 'Fisierul de font nu a putut fi incarcat', + aliasHint: 'Alias ZPL pentru această etichetă (1 caracter, A-Z sau 0-9)', + aliasAssigned: 'Alias ZPL atribuit acestei etichete', + manualMappingsHeading: 'Fonturi din imprimantă', + manualMappingsHint: 'Referință la fonturi deja prezente pe imprimantă, neîncărcate aici.', + addManualMapping: 'Adaugă font imprimantă', }, zebraPrint: { heading: 'Trimite la imprimanta Zebra', diff --git a/src/locales/sk.ts b/src/locales/sk.ts index 48d83555..7b5dac04 100644 --- a/src/locales/sk.ts +++ b/src/locales/sk.ts @@ -121,6 +121,14 @@ const sk = { defaultFontId: 'Písmo', defaultFontHeight: 'Výška (body)', defaultFontWidth: 'Šírka (dots)', + customFontsHeading: 'Vlastné písma', + customFontsHint: 'Aliasy pre písma uložené v tlačiarni.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Jeden znak: A-Z alebo 0-9', + customFontsDuplicateAlias: 'Duplicitný alias, uplatní sa iba posledné mapovanie.', + customFontsPath: 'Súbor písma (napr. E:ARIAL.TTF)', + customFontsAdd: 'Pridať mapovanie', + customFontsRemove: 'Odstrániť', }, app: { @@ -440,7 +448,13 @@ const sk = { upload: 'Nahrať', cancel: 'Zrušiť', delete: 'Odstrániť', + deleteConfirm: 'Odstrániť toto písmo z návrhu?', uploadError: 'Súbor písma sa nepodarilo načítať', + aliasHint: 'ZPL alias pre tento štítok (1 znak, A-Z alebo 0-9)', + aliasAssigned: 'Priradený ZPL alias pre tento štítok', + manualMappingsHeading: 'Písma uložené v tlačiarni', + manualMappingsHint: 'Odkaz na písma, ktoré sú už v tlačiarni, ale tu nie sú nahrané.', + addManualMapping: 'Pridať písmo tlačiarne', }, zebraPrint: { heading: 'Odoslať na tlačiareň Zebra', diff --git a/src/locales/sl.ts b/src/locales/sl.ts index 95e39544..3e9f50d3 100644 --- a/src/locales/sl.ts +++ b/src/locales/sl.ts @@ -121,6 +121,14 @@ const sl = { defaultFontId: 'Pisava', defaultFontHeight: 'Višina (točke)', defaultFontWidth: 'Širina (dots)', + customFontsHeading: 'Pisave po meri', + customFontsHint: 'Vzdevki za pisave shranjene v tiskalniku.', + customFontsAlias: 'ID', + customFontsAliasHint: 'En znak: A-Z ali 0-9', + customFontsDuplicateAlias: 'Podvojen vzdevek, uveljavi se le zadnja preslikava.', + customFontsPath: 'Datoteka pisave (npr. E:ARIAL.TTF)', + customFontsAdd: 'Dodaj preslikavo', + customFontsRemove: 'Odstrani', }, app: { @@ -440,7 +448,13 @@ const sl = { upload: 'Naloži', cancel: 'Prekliči', delete: 'Izbriši', + deleteConfirm: 'Odstrani to pisavo iz oblikovanja?', uploadError: 'Datoteke pisave ni bilo mogoče naložiti', + aliasHint: 'ZPL vzdevek za to etiketo (1 znak, A-Z ali 0-9)', + aliasAssigned: 'Dodeljen ZPL vzdevek za to etiketo', + manualMappingsHeading: 'Pisave v tiskalniku', + manualMappingsHint: 'Sklicevanje na pisave, ki so že v tiskalniku, vendar tukaj niso naložene.', + addManualMapping: 'Dodaj pisavo tiskalnika', }, zebraPrint: { heading: 'Pošlji na tiskalnik Zebra', diff --git a/src/locales/sr.ts b/src/locales/sr.ts index 3042623c..74b8a9d4 100644 --- a/src/locales/sr.ts +++ b/src/locales/sr.ts @@ -121,6 +121,14 @@ const sr = { defaultFontId: 'Фонт', defaultFontHeight: 'Висина (тачке)', defaultFontWidth: 'Ширина (dots)', + customFontsHeading: 'Прилагођени фонтови', + customFontsHint: 'Алијаси за фонтове сачуване у штампачу.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Један знак: A-Z или 0-9', + customFontsDuplicateAlias: 'Дупликат алијаса, примењује се само последње мапирање.', + customFontsPath: 'Датотека фонта (нпр. E:ARIAL.TTF)', + customFontsAdd: 'Додај мапирање', + customFontsRemove: 'Уклони', }, app: { @@ -440,7 +448,13 @@ const sr = { upload: 'Отпреми', cancel: 'Откажи', delete: 'Избриши', + deleteConfirm: 'Уклонити овај фонт из дизајна?', uploadError: 'Датотека фонта није могла бити учитана', + aliasHint: 'ZPL алијас за ову етикету (1 знак, A-Z или 0-9)', + aliasAssigned: 'Додељен ZPL алијас за ову етикету', + manualMappingsHeading: 'Фонтови на штампачу', + manualMappingsHint: 'Референца на фонтове који се већ налазе на штампачу, али нису пренети овде.', + addManualMapping: 'Додај фонт штампача', }, zebraPrint: { heading: 'Пошаљи на Zebra штампач', diff --git a/src/locales/sv.ts b/src/locales/sv.ts index 15ac834a..4a1749fa 100644 --- a/src/locales/sv.ts +++ b/src/locales/sv.ts @@ -121,6 +121,14 @@ const sv = { defaultFontId: 'Typsnitt', defaultFontHeight: 'Höjd (punkter)', defaultFontWidth: 'Bredd (dots)', + customFontsHeading: 'Egna typsnitt', + customFontsHint: 'Alias för typsnitt som finns i skrivaren.', + customFontsAlias: 'ID', + customFontsAliasHint: 'Ett tecken: A-Z eller 0-9', + customFontsDuplicateAlias: 'Dubblerat alias, endast den senaste mappningen gäller.', + customFontsPath: 'Typsnittsfil (t.ex. E:ARIAL.TTF)', + customFontsAdd: 'Lägg till mappning', + customFontsRemove: 'Ta bort', }, app: { @@ -440,7 +448,13 @@ const sv = { upload: 'Ladda upp', cancel: 'Avbryt', delete: 'Ta bort', + deleteConfirm: 'Ta bort detta typsnitt från designen?', uploadError: 'Det gick inte att ladda typsnittsfilen', + aliasHint: 'ZPL-alias för denna etikett (1 tecken, A-Z eller 0-9)', + aliasAssigned: 'Tilldelat ZPL-alias för denna etikett', + manualMappingsHeading: 'Typsnitt i skrivaren', + manualMappingsHint: 'Referera till typsnitt som redan finns på skrivaren men inte är uppladdade här.', + addManualMapping: 'Lägg till skrivartypsnitt', }, zebraPrint: { heading: 'Skicka till Zebra-skrivare', diff --git a/src/locales/tr.ts b/src/locales/tr.ts index 3c186cab..ea6e1f2b 100644 --- a/src/locales/tr.ts +++ b/src/locales/tr.ts @@ -121,6 +121,14 @@ const tr = { defaultFontId: 'Yazı tipi', defaultFontHeight: 'Yükseklik (nokta)', defaultFontWidth: 'Genişlik (dots)', + customFontsHeading: 'Özel yazı tipleri', + customFontsHint: 'Yazıcıda kayıtlı yazı tipleri için takma adlar.', + customFontsAlias: 'Kimlik', + customFontsAliasHint: 'Tek karakter: A-Z veya 0-9', + customFontsDuplicateAlias: 'Yinelenen takma ad, yalnızca son eşleme geçerli olur.', + customFontsPath: 'Yazı tipi dosyası (örn. E:ARIAL.TTF)', + customFontsAdd: 'Eşleme ekle', + customFontsRemove: 'Kaldır', }, app: { @@ -440,7 +448,13 @@ const tr = { upload: 'Yükle', cancel: 'İptal', delete: 'Sil', + deleteConfirm: 'Bu yazı tipi tasarımdan kaldırılsın mı?', uploadError: 'Yazı tipi dosyası yüklenemedi', + aliasHint: 'Bu etiket için ZPL takma adı (1 karakter, A-Z veya 0-9)', + aliasAssigned: 'Bu etikete atanmış ZPL takma adı', + manualMappingsHeading: 'Yazıcıda kayıtlı yazı tipleri', + manualMappingsHint: 'Yazıcıda zaten bulunan ancak buraya yüklenmemiş yazı tiplerine referans verir.', + addManualMapping: 'Yazıcı yazı tipi ekle', }, zebraPrint: { heading: 'Zebra yazıcıya gönder', diff --git a/src/locales/zh-hans.ts b/src/locales/zh-hans.ts index bf373ee7..1456e645 100644 --- a/src/locales/zh-hans.ts +++ b/src/locales/zh-hans.ts @@ -121,6 +121,14 @@ const zhHans = { defaultFontId: '字体', defaultFontHeight: '高度 (点)', defaultFontWidth: '宽度 (dots)', + customFontsHeading: '自定义字体', + customFontsHint: '为打印机中已有的字体设置别名。', + customFontsAlias: 'ID', + customFontsAliasHint: '单个字符:A-Z 或 0-9', + customFontsDuplicateAlias: '重复别名, 仅最后一个映射生效。', + customFontsPath: '字体文件 (例如 E:ARIAL.TTF)', + customFontsAdd: '添加映射', + customFontsRemove: '移除', }, app: { @@ -440,7 +448,13 @@ const zhHans = { upload: '上传', cancel: '取消', delete: '删除', + deleteConfirm: '从设计中移除此字体?', uploadError: '无法加载字体文件', + aliasHint: '此标签的 ZPL 别名 (1 字符, A-Z 或 0-9)', + aliasAssigned: '此标签的已分配 ZPL 别名', + manualMappingsHeading: '打印机内置字体', + manualMappingsHint: '引用打印机中已有但未在此上传的字体。', + addManualMapping: '添加打印机字体', }, zebraPrint: { heading: '发送到 Zebra 打印机', diff --git a/src/locales/zh-hant.ts b/src/locales/zh-hant.ts index 202e3c2b..60c954a1 100644 --- a/src/locales/zh-hant.ts +++ b/src/locales/zh-hant.ts @@ -121,6 +121,14 @@ const zhHant = { defaultFontId: '字型', defaultFontHeight: '高度 (點)', defaultFontWidth: '寬度 (dots)', + customFontsHeading: '自訂字型', + customFontsHint: '為印表機中已有的字型設定別名。', + customFontsAlias: 'ID', + customFontsAliasHint: '單一字元:A-Z 或 0-9', + customFontsDuplicateAlias: '重複別名, 僅最後一個對應生效。', + customFontsPath: '字型檔案 (例如 E:ARIAL.TTF)', + customFontsAdd: '新增對應', + customFontsRemove: '移除', }, app: { @@ -440,7 +448,13 @@ const zhHant = { upload: '上傳', cancel: '取消', delete: '刪除', + deleteConfirm: '從設計中移除此字型?', uploadError: '無法載入字體檔案', + aliasHint: '此標籤的 ZPL 別名 (1 字元, A-Z 或 0-9)', + aliasAssigned: '此標籤的已指派 ZPL 別名', + manualMappingsHeading: '印表機內建字型', + manualMappingsHint: '參照印表機中已有但未在此上傳的字型。', + addManualMapping: '新增印表機字型', }, zebraPrint: { heading: '傳送至 Zebra 印表機', diff --git a/src/types/ObjectType.ts b/src/types/ObjectType.ts index bbc4baaf..35adfc5d 100644 --- a/src/types/ObjectType.ts +++ b/src/types/ObjectType.ts @@ -1,6 +1,14 @@ import type React from 'react'; import { z } from 'zod'; +/** A single ^CW mapping: a 1-character alias [A-Z0-9] paired with a font + * path on the printer's storage (e.g. "E:ARIAL.TTF"). */ +export const customFontMappingSchema = z.object({ + alias: z.string().regex(/^[A-Z0-9]$/), + path: z.string().min(1), +}); +export type CustomFontMapping = z.infer; + export const labelConfigSchema = z.object({ widthMm: z.number(), heightMm: z.number(), @@ -38,6 +46,10 @@ export const labelConfigSchema = z.object({ defaultFontHeight: z.number().int().positive().optional(), /** ^CF width param. Spec allows 0 → printer auto-derives from height. */ defaultFontWidth: z.number().int().min(0).optional(), + /** ^CW alias→path mappings emitted at the top of the label. Each entry + * registers a single-char identifier ([A-Z0-9]) that ^A{alias} fields + * can reference instead of the verbose ^A@…E:font.TTF form. */ + customFonts: z.array(customFontMappingSchema).optional(), }); export type LabelConfig = z.infer;