Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ Select several objects with Shift-click or a lasso. Position and size changes ap

### 4. Print or export

The **ZPL** panel at the bottom shows the generated ZPL, **Copy** puts it on the clipboard. The canvas shows the label as you design it. **Preview** adds an alternative rendering from the connected printer (desktop) or, with consent, from the third-party service [Labelary](https://labelary.com/).
The **ZPL** panel at the bottom shows the generated ZPL, **Copy** puts it on the clipboard. The canvas is ZPLab's rendering of the label. A second rendering comes from the preview renderer under **File → Settings… → App → Preview**: the connected printer (desktop) or, with consent, the third-party service [Labelary](https://labelary.com/). **Preview** shows it for comparison.

- **File → Export ZPL:** saves a `.zpl` file, or `.prn` where the save dialog offers file types
- **File → Send to Zebra Printer:** opens the send dialog. It sends over the network, through the Zebra Browser Print agent in the browser, or through the system spooler or USB on desktop.
- **File → Export PDF:** saves one PDF page per label page, rendered by the preview renderer. With the renderer off it holds the current page only. A batch PDF holds one page per data row.
- **File → Print as Image (browser):** opens the rendered label, then the browser print dialog
- **File → Export PDF:** saves one PDF page per label page, rendered by the preview renderer. With the renderer off, ZPLab captures the canvas, so the PDF holds the current page only. A batch PDF needs the renderer and holds one page per data row.
- **File → Print as Image (browser):** renders the current page with the same renderer, then opens the browser print dialog

### 5. Save the design

Expand All @@ -97,7 +97,7 @@ The **ZPL** panel highlights syntax and collapses long blocks of image data. Sel

The **command list** left of the code filters as you search. The **ZPL reference** on the right follows the cursor. Click a command to pin its details. The details also show the syntax, a parameter table and an example where the reference has them. A double-click or the right-click menu inserts the command at the cursor. A chevron folds each pane to a rail. Click the rail to bring it back.

While you edit, the canvas shows a live preview. Canvas editing and the **Properties** tab are disabled. Page switching stays enabled. The editor refuses source that is too large or has mismatched `^XA`/`^XZ` commands, and marks the mismatches. Click a mark to insert the missing command.
While you edit, the canvas renders the source. Canvas editing and the **Properties** tab are disabled. Page switching stays enabled. The editor refuses source that is too large or has mismatched `^XA`/`^XZ` commands, and marks the mismatches. Click a mark to insert the missing command.

- **Apply** or leaving the panel commits your changes.
- `Esc` or **Cancel** discards them.
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/packaging/linux/de.u8array.zplab.metainfo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
<li>Typed payloads for QR Code, Data Matrix and Aztec: URLs, Wi-Fi, contacts, email, phone, SMS and coordinates, plus GS1 Digital Links</li>
<li>Batch printing: map label variables to CSV, Excel or database columns and print one label per row</li>
<li>Printing over raw TCP, the system print queue, or USB</li>
<li>Previews rendered through Labelary, or by the connected printer's own firmware</li>
<li>An optional second rendering of the label, from Labelary or from the connected printer's own firmware, to compare against the canvas</li>
<li>An MCP server that lets a local AI assistant read, build and validate labels, and edit the open design directly</li>
<li>32 interface languages, light and dark theme</li>
<li>MIT-licensed, with no account and no backend</li>
Expand Down
9 changes: 9 additions & 0 deletions src/components/PrinterSettings/PreviewSettingsTab.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ describe("PreviewSettingsTab", () => {
expect(useLabelStore.getState().previewProvider).toBe("none");
expect(r.getByLabelText(loc.labelaryConsent)).toBeTruthy();
expect(r.queryByText(loc.apiHeading)).toBeNull();
expect(r.getByText(loc.labelaryIdleHint, { exact: false })).toBeTruthy();
expect(r.queryByText(en.output.previewNoticeBody, { exact: false })).toBeNull();
});

it("keeps the notice when a stored printer way falls back to Labelary on the web", () => {
act(() => useLabelStore.setState({ previewProvider: "printer" }));
const r = render(<PreviewSettingsTab />);
expect(r.getByText(en.output.previewNoticeBody, { exact: false })).toBeTruthy();
expect(r.queryByText(loc.labelaryIdleHint, { exact: false })).toBeNull();
});

it("shows the stored choice and says a build without Labelary has no renderer", () => {
Expand Down
3 changes: 2 additions & 1 deletion src/components/PrinterSettings/PreviewSettingsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ export function PreviewSettingsTab() {
<p className="text-[10px] text-muted leading-relaxed max-w-md">
{publicHost ? (
<>
{t.output.previewNoticeBody}{" "}
{/* The notice must stand wherever Labelary renders or is about to: a stored printer choice degrades to it on the web. */}
{chosen === "labelary" || provider === "labelary" ? t.output.previewNoticeBody : loc.labelaryIdleHint}{" "}
{/* The plans/retention link is about the public service; a
custom endpoint is the operator's own, so omit it there. */}
<a
Expand Down
3 changes: 2 additions & 1 deletion src/locales/ar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -835,11 +835,12 @@ const ar = {
providerPrinterHint: 'تعرض الطابعة الملصق باستخدام برنامجها الثابت الخاص؛ لا يتم طباعة أي شيء.',
providerPrinterDesktopOnly: 'يتطلب تطبيق سطح المكتب.',
providerNone: 'إيقاف',
providerNoneHint: 'لا توجد معاينة مُصيَّرة. تبقى اللوحة هي العرض الوحيد.',
providerNoneHint: 'يُخفي المعاينة. يستخدم تصدير PDF والطباعة كصورة اللوحة.',
providerInUseFmt: 'نشط حاليًا: {provider}',
printerTargetHint: 'يتم ضبط الطابعة ضمن التطبيق، الطابعة.',
privacyHeading: 'الخصوصية',
labelaryConsent: 'معاينة Labelary',
labelaryIdleHint: 'يُستخدم Labelary فقط عندما يكون العارض المحدد. تظل الموافقة سارية حتى تسحبها.',
labelaryHint: 'يرسل ZPL الخاص بك إلى خادم Labelary المُهيَّأ للتصيير.',
apiHeading: 'Labelary API',
apiHost: 'عنوان URL للخادم',
Expand Down
3 changes: 2 additions & 1 deletion src/locales/bg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -835,11 +835,12 @@ const bg = {
providerPrinterHint: 'Принтерът рендира етикета със собствения си фърмуер; нищо не се отпечатва.',
providerPrinterDesktopOnly: 'Изисква настолното приложение.',
providerNone: 'Изключено',
providerNoneHint: 'Няма изобразена визуализация. Платното остава единственият изглед.',
providerNoneHint: 'Скрива прегледа. Експортът на PDF и печатът като изображение използват платното.',
providerInUseFmt: 'В момента активен: {provider}',
printerTargetHint: 'Принтерът се задава под Приложение, Принтер.',
privacyHeading: 'Поверителност',
labelaryConsent: 'Labelary преглед',
labelaryIdleHint: 'Labelary се използва само докато е избраният визуализатор. Съгласието остава валидно, докато не го оттеглите.',
labelaryHint: 'Изпраща вашия ZPL до конфигурирания Labelary сървър за рендиране.',
apiHeading: 'Labelary API',
apiHost: 'URL на сървъра',
Expand Down
3 changes: 2 additions & 1 deletion src/locales/cs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -835,11 +835,12 @@ const cs = {
providerPrinterHint: 'Tiskárna vykreslí štítek pomocí vlastního firmwaru; nic se netiskne.',
providerPrinterDesktopOnly: 'Vyžaduje desktopovou aplikaci.',
providerNone: 'Vypnuto',
providerNoneHint: 'Žádný vykreslený náhled. Plátno zůstává jediným zobrazením.',
providerNoneHint: 'Skryje náhled. Export PDF a tisk jako obrázek používají plátno.',
providerInUseFmt: 'Aktuálně aktivní: {provider}',
printerTargetHint: 'Tiskárna se nastavuje pod Aplikace, Tiskárna.',
privacyHeading: 'Soukromí',
labelaryConsent: 'Náhled Labelary',
labelaryIdleHint: 'Labelary se používá pouze tehdy, když je vybraným vykreslovačem. Souhlas platí, dokud ho neodvoláte.',
labelaryHint: 'Odesílá váš ZPL na nakonfigurovaný Labelary server pro vykreslení.',
apiHeading: 'Labelary API',
apiHost: 'URL serveru',
Expand Down
3 changes: 2 additions & 1 deletion src/locales/da.ts
Original file line number Diff line number Diff line change
Expand Up @@ -835,11 +835,12 @@ const da = {
providerPrinterHint: 'Printeren gengiver etiketten med sin egen firmware; der udskrives ikke noget.',
providerPrinterDesktopOnly: 'Kræver desktopappen.',
providerNone: 'Fra',
providerNoneHint: 'Ingen gengivet forhåndsvisning. Lærredet forbliver den eneste visning.',
providerNoneHint: 'Skjuler forhåndsvisningen. PDF-eksport og udskrift som billede bruger lærredet.',
providerInUseFmt: 'Aktiv nu: {provider}',
printerTargetHint: 'Printeren indstilles under App, Printer.',
privacyHeading: 'Privatliv',
labelaryConsent: 'Labelary-forhåndsvisning',
labelaryIdleHint: 'Labelary bruges kun, når det er den valgte renderer. Samtykket gælder, indtil du tilbagekalder det.',
labelaryHint: 'Sender dit ZPL til den konfigurerede Labelary-server til gengivelse.',
apiHeading: 'Labelary API',
apiHost: 'Server-URL',
Expand Down
3 changes: 2 additions & 1 deletion src/locales/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -835,11 +835,12 @@ const de = {
providerPrinterHint: 'Der Drucker rendert das Label mit seiner eigenen Firmware; es wird nichts gedruckt.',
providerPrinterDesktopOnly: 'Nur in der Desktop-App verfügbar.',
providerNone: 'Aus',
providerNoneHint: 'Keine gerenderte Vorschau. Der Canvas bleibt die einzige Ansicht.',
providerNoneHint: 'Blendet die Vorschau aus. PDF-Export und Bilddruck nutzen den Canvas.',
providerInUseFmt: 'Gerade aktiv: {provider}',
printerTargetHint: 'Der Drucker wird unter App, Drucker eingestellt.',
privacyHeading: 'Datenschutz',
labelaryConsent: 'Labelary-Vorschau',
labelaryIdleHint: 'Labelary wird nur verwendet, während es als Renderer ausgewählt ist. Die Zustimmung bleibt gültig, bis du sie widerrufst.',
labelaryHint: 'Sendet dein ZPL zum konfigurierten Labelary-Server zum Rendern.',
apiHeading: 'Labelary API',
apiHost: 'Server-URL',
Expand Down
3 changes: 2 additions & 1 deletion src/locales/el.ts
Original file line number Diff line number Diff line change
Expand Up @@ -835,11 +835,12 @@ const el = {
providerPrinterHint: 'Ο εκτυπωτής αποδίδει την ετικέτα με το δικό του firmware· δεν εκτυπώνεται τίποτα.',
providerPrinterDesktopOnly: 'Απαιτεί την εφαρμογή υπολογιστή.',
providerNone: 'Ανενεργό',
providerNoneHint: 'Καμία αποδοσμένη προεπισκόπηση. Ο καμβάς παραμένει η μόνη προβολή.',
providerNoneHint: 'Αποκρύπτει την προεπισκόπηση. Η εξαγωγή PDF και η εκτύπωση ως εικόνα χρησιμοποιούν τον καμβά.',
providerInUseFmt: 'Ενεργό αυτήν τη στιγμή: {provider}',
printerTargetHint: 'Ο εκτυπωτής ρυθμίζεται στην Εφαρμογή, Εκτυπωτής.',
privacyHeading: 'Απόρρητο',
labelaryConsent: 'Προεπισκόπηση Labelary',
labelaryIdleHint: 'Το Labelary χρησιμοποιείται μόνο όσο είναι η επιλεγμένη μηχανή απόδοσης. Η συναίνεση παραμένει έγκυρη έως ότου την ανακαλέσετε.',
labelaryHint: 'Στέλνει το ZPL σας στον διαμορφωμένο διακομιστή Labelary για απόδοση.',
apiHeading: 'Labelary API',
apiHost: 'URL διακομιστή',
Expand Down
3 changes: 2 additions & 1 deletion src/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -835,11 +835,12 @@ const en = {
providerPrinterHint: 'The printer renders the label with its own firmware; nothing is printed.',
providerPrinterDesktopOnly: 'Requires the desktop app.',
providerNone: 'Off',
providerNoneHint: 'No rendered preview. The canvas stays the only view.',
providerNoneHint: 'Hides Preview. PDF export and image print use the canvas.',
providerInUseFmt: 'Currently active: {provider}',
printerTargetHint: 'The printer is set under App, Printer.',
privacyHeading: 'Privacy',
labelaryConsent: 'Labelary preview',
labelaryIdleHint: 'Labelary is used only while it is the selected renderer. The consent stands until you revoke it.',
labelaryHint: 'Sends your ZPL to the configured Labelary server for rendering.',
apiHeading: 'Labelary API',
apiHost: 'Server URL',
Expand Down
3 changes: 2 additions & 1 deletion src/locales/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -835,11 +835,12 @@ const es = {
providerPrinterHint: 'La impresora renderiza la etiqueta con su propio firmware; no se imprime nada.',
providerPrinterDesktopOnly: 'Requiere la aplicación de escritorio.',
providerNone: 'Desactivado',
providerNoneHint: 'Sin vista previa renderizada. El lienzo sigue siendo la única vista.',
providerNoneHint: 'Oculta la vista previa. La exportación a PDF y la impresión como imagen usan el lienzo.',
providerInUseFmt: 'Actualmente activo: {provider}',
printerTargetHint: 'La impresora se configura en App, Impresora.',
privacyHeading: 'Privacidad',
labelaryConsent: 'Vista previa de Labelary',
labelaryIdleHint: 'Labelary solo se usa mientras sea el renderizador seleccionado. El consentimiento se mantiene vigente hasta que lo revoques.',
labelaryHint: 'Envía tu ZPL al servidor Labelary configurado para su renderización.',
apiHeading: 'Labelary API',
apiHost: 'URL del servidor',
Expand Down
3 changes: 2 additions & 1 deletion src/locales/et.ts
Original file line number Diff line number Diff line change
Expand Up @@ -835,11 +835,12 @@ const et = {
providerPrinterHint: 'Printer renderdab sildi oma püsivara abil; midagi ei prindita.',
providerPrinterDesktopOnly: 'Nõuab lauaarvutirakendust.',
providerNone: 'Väljas',
providerNoneHint: 'Renderdatud eelvaadet pole. Lõuend jääb ainsaks vaateks.',
providerNoneHint: 'Peidab eelvaate. PDF-eksport ja pildina printimine kasutavad lõuendit.',
providerInUseFmt: 'Praegu aktiivne: {provider}',
printerTargetHint: 'Printer seadistatakse jaotises Rakendus, Printer.',
privacyHeading: 'Privaatsus',
labelaryConsent: 'Labelary eelvaade',
labelaryIdleHint: 'Labelaryt kasutatakse ainult seni, kuni see on valitud renderdaja. Nõusolek kehtib, kuni selle tühistate.',
labelaryHint: 'Saadab teie ZPL-i seadistatud Labelary serverisse renderdamiseks.',
apiHeading: 'Labelary API',
apiHost: 'Serveri URL',
Expand Down
3 changes: 2 additions & 1 deletion src/locales/fa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -835,11 +835,12 @@ const fa = {
providerPrinterHint: 'چاپگر برچسب را با فریمور خودش رندر می‌کند؛ چیزی چاپ نمی‌شود.',
providerPrinterDesktopOnly: 'به برنامه دسکتاپ نیاز دارد.',
providerNone: 'خاموش',
providerNoneHint: 'پیش‌نمایش رندرشده‌ای وجود ندارد. بوم تنها نمای باقی‌مانده است.',
providerNoneHint: 'پیش‌نمایش را پنهان می‌کند. خروجی PDF و چاپ به‌صورت تصویر از بوم استفاده می‌کنند.',
providerInUseFmt: 'اکنون فعال: {provider}',
printerTargetHint: 'چاپگر در برنامه، چاپگر تنظیم می‌شود.',
privacyHeading: 'حریم خصوصی',
labelaryConsent: 'پیش‌نمایش Labelary',
labelaryIdleHint: 'Labelary فقط زمانی استفاده می‌شود که موتور انتخاب‌شده باشد. رضایت تا زمان لغو شما معتبر باقی می‌ماند.',
labelaryHint: 'ZPL شما را برای رندرینگ به سرور Labelary پیکربندی‌شده می‌فرستد.',
apiHeading: 'Labelary API',
apiHost: 'نشانی URL سرور',
Expand Down
3 changes: 2 additions & 1 deletion src/locales/fi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -835,11 +835,12 @@ const fi = {
providerPrinterHint: 'Tulostin renderöi etiketin omalla laiteohjelmistollaan; mitään ei tulosteta.',
providerPrinterDesktopOnly: 'Vaatii työpöytäsovelluksen.',
providerNone: 'Pois',
providerNoneHint: 'Ei renderöityä esikatselua. Kangas pysyy ainoana näkymänä.',
providerNoneHint: 'Piilottaa esikatselun. PDF-vienti ja kuvana tulostus käyttävät kangasta.',
providerInUseFmt: 'Tällä hetkellä käytössä: {provider}',
printerTargetHint: 'Tulostin asetetaan kohdassa Sovellus, Tulostin.',
privacyHeading: 'Tietosuoja',
labelaryConsent: 'Labelary-esikatselu',
labelaryIdleHint: 'Labelarya käytetään vain, kun se on valittu renderöijä. Suostumus on voimassa, kunnes peruutat sen.',
labelaryHint: 'Lähettää ZPL:si määritetylle Labelary-palvelimelle renderöintiä varten.',
apiHeading: 'Labelary API',
apiHost: 'Palvelimen URL',
Expand Down
3 changes: 2 additions & 1 deletion src/locales/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -835,11 +835,12 @@ const fr = {
providerPrinterHint: "L'imprimante restitue l'étiquette avec son propre micrologiciel ; rien n'est imprimé.",
providerPrinterDesktopOnly: "Nécessite l'application de bureau.",
providerNone: 'Désactivé',
providerNoneHint: 'Aucun aperçu rendu. Le canevas reste la seule vue.',
providerNoneHint: "Masque l'aperçu. L'export PDF et l'impression en image utilisent le canevas.",
providerInUseFmt: 'Actuellement actif : {provider}',
printerTargetHint: "L'imprimante se règle dans App, Imprimante.",
privacyHeading: 'Confidentialité',
labelaryConsent: 'Aperçu Labelary',
labelaryIdleHint: "Labelary n'est utilisé que lorsqu'il est le moteur d'aperçu sélectionné. Le consentement reste valable jusqu'à ce que vous le révoquiez.",
labelaryHint: 'Envoie votre ZPL au serveur Labelary configuré pour le rendu.',
apiHeading: 'Labelary API',
apiHost: 'URL du serveur',
Expand Down
3 changes: 2 additions & 1 deletion src/locales/he.ts
Original file line number Diff line number Diff line change
Expand Up @@ -835,11 +835,12 @@ const he = {
providerPrinterHint: 'המדפסת מעבדת את התווית באמצעות הקושחה שלה; דבר לא מודפס בפועל.',
providerPrinterDesktopOnly: 'דורש את אפליקציית שולחן העבודה.',
providerNone: 'כבוי',
providerNoneHint: 'אין תצוגה מקדימה מוצגת. הקנבס נשאר התצוגה היחידה.',
providerNoneHint: 'מסתיר את התצוגה המקדימה. ייצוא PDF והדפסה כתמונה משתמשים בקנבס.',
providerInUseFmt: 'פעיל כעת: {provider}',
printerTargetHint: 'המדפסת מוגדרת תחת אפליקציה, מדפסת.',
privacyHeading: 'פרטיות',
labelaryConsent: 'תצוגה מקדימה של Labelary',
labelaryIdleHint: 'Labelary נמצא בשימוש רק כאשר הוא מנוע התצוגה המקדימה הנבחר. ההסכמה תקפה עד שתבטל אותה.',
labelaryHint: 'שולח את ה-ZPL שלך לשרת Labelary המוגדר לצורך עיבוד.',
apiHeading: 'Labelary API',
apiHost: 'כתובת URL של השרת',
Expand Down
Loading
Loading