diff --git a/src/lib/useT.ts b/src/lib/useT.ts index 9ff5fba..2d6839a 100644 --- a/src/lib/useT.ts +++ b/src/lib/useT.ts @@ -1,7 +1,7 @@ import { useLabelStore } from '../store/labelStore'; -import { locales } from '../locales'; +import { locales, type Translations } from '../locales'; -export function useT() { +export function useT(): Translations { const locale = useLabelStore((s) => s.locale); return locales[locale]; } diff --git a/src/lib/zplParser.ts b/src/lib/zplParser.ts index 02a6c1f..7535d40 100644 --- a/src/lib/zplParser.ts +++ b/src/lib/zplParser.ts @@ -429,6 +429,7 @@ export function parseZPL(zpl: string, dpmm = 8): ParsedZPL { height: bcHeight, moduleWidth: byModuleWidth, printInterpretation: bcInterp, + checkDigit: false, // EAN-13 has no user-controlled check digit (^BE auto-appends). rotation: bcRotation, } satisfies Ean13Props, posType, diff --git a/src/locales/index.ts b/src/locales/index.ts index 69b641f..6ca1b84 100644 --- a/src/locales/index.ts +++ b/src/locales/index.ts @@ -78,6 +78,11 @@ export const locales = { export type LocaleCode = keyof typeof locales; +/** Shape of a single locale dictionary, derived from the registered locales. + * Use this when a non-React module needs the translation type without + * pulling in the useT hook. */ +export type Translations = (typeof locales)[LocaleCode]; + export const localeNames: Record = { en: 'English', de: 'Deutsch', diff --git a/src/registry/barcode1d.tsx b/src/registry/barcode1d.tsx index 32f76a9..1f9fcdd 100644 --- a/src/registry/barcode1d.tsx +++ b/src/registry/barcode1d.tsx @@ -1,5 +1,6 @@ import type { ObjectTypeDefinition, ObjectGroup, LabelObjectBase } from '../types/ObjectType'; import { useT } from '../lib/useT'; +import type { Translations } from '../locales'; import { inputCls, labelCls } from '../components/Properties/styles'; import { fieldPos, fdField } from './zplHelpers'; import { commitHeightTransform } from './transformHelpers'; @@ -24,8 +25,10 @@ interface Barcode1DConfig { hasCheckDigit: boolean; /** Build the ZPL barcode command (e.g. `^BUN,100,Y,N,N`). */ zplCommand: (p: Barcode1DProps) => string; - /** Locale key under `t.registry[localeKey]`. Must match en.ts shape. */ - localeKey: string; + /** Per-symbology locale block selector — TS verifies the returned shape + * conforms to BarcodeLocale at every call site, so a missing or renamed + * `t.registry.` is a compile error rather than a runtime undefined. */ + locale: (t: Translations) => BarcodeLocale; group: ObjectGroup; /** * Explicit wide-to-narrow ratio for the ^BY command. @@ -90,7 +93,7 @@ export function createBarcode1D(config: Barcode1DConfig): ObjectTypeDefinition { const t = useT(); - const loc = (t.registry as unknown as Record)[config.localeKey] ?? {} as BarcodeLocale; + const loc = config.locale(t); const p = obj.props; return (
diff --git a/src/registry/codabar.tsx b/src/registry/codabar.tsx index 66e8967..e0c9825 100644 --- a/src/registry/codabar.tsx +++ b/src/registry/codabar.tsx @@ -6,7 +6,7 @@ export const codabar = createBarcode1D({ icon: "CBA", defaultContent: "A12345A", hasCheckDigit: true, - localeKey: "codabar", + locale: (t) => t.registry.codabar, group: 'code-1d', contentSpec: { charset: '0-9A-Da-d\\-$:/.+' }, zplCommand: (p) => { diff --git a/src/registry/code11.tsx b/src/registry/code11.tsx index 218a816..a296204 100644 --- a/src/registry/code11.tsx +++ b/src/registry/code11.tsx @@ -6,7 +6,7 @@ export const code11 = createBarcode1D({ icon: "C11", defaultContent: "12345", hasCheckDigit: true, - localeKey: "code11", + locale: (t) => t.registry.code11, group: 'code-1d', contentSpec: { charset: '0-9\\-' }, zplCommand: (p) => { diff --git a/src/registry/code128.tsx b/src/registry/code128.tsx index 5430f44..5f82e55 100644 --- a/src/registry/code128.tsx +++ b/src/registry/code128.tsx @@ -1,101 +1,16 @@ -import type { ObjectTypeDefinition } from '../types/ObjectType'; -import { useT } from '../lib/useT'; -import { inputCls, labelCls } from '../components/Properties/styles'; -import { fieldPos, fdField } from './zplHelpers'; -import { commitHeightTransform } from './transformHelpers'; -import { type ZplRotation } from './rotation'; -import { RotationSelect } from '../components/Properties/RotationSelect'; -import { NumberInput } from '../components/Properties/NumberInput'; +import { createBarcode1D } from './barcode1d'; +export type { Barcode1DProps as Code128Props } from './barcode1d'; -export interface Code128Props { - content: string; - height: number; - moduleWidth: number; - printInterpretation: boolean; - checkDigit: boolean; - rotation: ZplRotation; -} - -export const code128: ObjectTypeDefinition = { +export const code128 = createBarcode1D({ label: 'Code 128', icon: '|||', - group: 'code-1d' as const, - defaultProps: { - content: '12345678', - height: 100, - moduleWidth: 2, - printInterpretation: true, - checkDigit: false, - rotation: 'N', - }, - defaultSize: { width: 300, height: 120 }, - - commitTransform: commitHeightTransform, - - toZPL: (obj) => { - const p = obj.props; + defaultContent: '12345678', + hasCheckDigit: true, + locale: (t) => t.registry.code128, + group: 'code-1d', + zplCommand: (p) => { const interp = p.printInterpretation ? 'Y' : 'N'; const check = p.checkDigit ? 'Y' : 'N'; - return [ - `^BY${p.moduleWidth}`, - fieldPos(obj), - `^BC${p.rotation},${p.height},${interp},N,${check}`, - fdField(p.content), - ].filter(Boolean).join(''); - }, - - PropertiesPanel: ({ obj, onChange }) => { - const t = useT(); - const p = obj.props; - return ( -
-
- - onChange({ content: e.target.value })} - /> -
- - onChange({ height })} - /> - - onChange({ moduleWidth })} - /> - -
- - -
- - onChange({ rotation })} /> -
- ); + return `^BC${p.rotation},${p.height},${interp},N,${check}`; }, -}; +}); diff --git a/src/registry/code39.tsx b/src/registry/code39.tsx index ed6b887..e7722e2 100644 --- a/src/registry/code39.tsx +++ b/src/registry/code39.tsx @@ -1,104 +1,20 @@ -import type { ObjectTypeDefinition } from '../types/ObjectType'; -import { useT } from '../lib/useT'; -import { inputCls, labelCls } from '../components/Properties/styles'; -import { fieldPos, fdField } from './zplHelpers'; -import { commitHeightTransform } from './transformHelpers'; -import { filterContent, type ContentSpec } from './contentSpec'; -import { type ZplRotation } from './rotation'; -import { RotationSelect } from '../components/Properties/RotationSelect'; -import { NumberInput } from '../components/Properties/NumberInput'; +import { createBarcode1D } from './barcode1d'; +import type { ContentSpec } from './contentSpec'; +export type { Barcode1DProps as Code39Props } from './barcode1d'; const code39Spec: ContentSpec = { charset: '0-9A-Za-z\\-. $/+%' }; -export interface Code39Props { - content: string; - height: number; - moduleWidth: number; - printInterpretation: boolean; - checkDigit: boolean; - rotation: ZplRotation; -} - -export const code39: ObjectTypeDefinition = { +export const code39 = createBarcode1D({ label: 'Code 39', icon: '|·|', + defaultContent: 'CODE39', + hasCheckDigit: true, + locale: (t) => t.registry.code39, group: 'code-1d', - defaultProps: { - content: 'CODE39', - height: 100, - moduleWidth: 2, - printInterpretation: true, - checkDigit: false, - rotation: 'N', - }, - defaultSize: { width: 300, height: 120 }, - - commitTransform: commitHeightTransform, - - toZPL: (obj) => { - const p = obj.props; + contentSpec: code39Spec, + zplCommand: (p) => { const interp = p.printInterpretation ? 'Y' : 'N'; const check = p.checkDigit ? 'Y' : 'N'; - return [ - `^BY${p.moduleWidth}`, - fieldPos(obj), - `^B3${p.rotation},${check},${p.height},${interp},N`, - fdField(p.content), - ].filter(Boolean).join(''); - }, - - PropertiesPanel: ({ obj, onChange }) => { - const t = useT(); - const p = obj.props; - return ( -
-
- - onChange({ content: filterContent(e.target.value, code39Spec) })} - /> -
- - onChange({ height })} - /> - - onChange({ moduleWidth })} - /> - -
- - -
- - onChange({ rotation })} /> -
- ); + return `^B3${p.rotation},${check},${p.height},${interp},N`; }, -}; +}); diff --git a/src/registry/code93.tsx b/src/registry/code93.tsx index d815f1f..00b5c8e 100644 --- a/src/registry/code93.tsx +++ b/src/registry/code93.tsx @@ -6,7 +6,7 @@ export const code93 = createBarcode1D({ icon: '|93|', defaultContent: 'CODE93', hasCheckDigit: true, - localeKey: 'code93', + locale: (t) => t.registry.code93, group: 'code-1d', zplCommand: (p) => { const interp = p.printInterpretation ? 'Y' : 'N'; diff --git a/src/registry/ean13.tsx b/src/registry/ean13.tsx index 1cc9d16..1f27eca 100644 --- a/src/registry/ean13.tsx +++ b/src/registry/ean13.tsx @@ -1,92 +1,19 @@ -import type { ObjectTypeDefinition } from '../types/ObjectType'; -import { useT } from '../lib/useT'; -import { inputCls, labelCls } from '../components/Properties/styles'; -import { fieldPos, fdField } from './zplHelpers'; -import { commitHeightTransform } from './transformHelpers'; -import { filterContent, type ContentSpec } from './contentSpec'; -import { type ZplRotation } from './rotation'; -import { RotationSelect } from '../components/Properties/RotationSelect'; -import { NumberInput } from '../components/Properties/NumberInput'; +import { createBarcode1D } from './barcode1d'; +import type { ContentSpec } from './contentSpec'; +export type { Barcode1DProps as Ean13Props } from './barcode1d'; const ean13Spec: ContentSpec = { charset: '0-9', maxLength: 12 }; -export interface Ean13Props { - content: string; // 12 digits — ZPL appends the check digit automatically - height: number; - moduleWidth: number; - printInterpretation: boolean; - rotation: ZplRotation; -} - -export const ean13: ObjectTypeDefinition = { +export const ean13 = createBarcode1D({ label: 'EAN-13', icon: 'EAN', + defaultContent: '590123412345', + hasCheckDigit: false, + locale: (t) => t.registry.ean13, group: 'code-1d', - defaultProps: { - content: '590123412345', - height: 100, - moduleWidth: 2, - printInterpretation: true, - rotation: 'N', - }, - defaultSize: { width: 300, height: 120 }, - - commitTransform: commitHeightTransform, - - toZPL: (obj) => { - const p = obj.props; + contentSpec: ean13Spec, + zplCommand: (p) => { const interp = p.printInterpretation ? 'Y' : 'N'; - return [ - `^BY${p.moduleWidth}`, - fieldPos(obj), - `^BE${p.rotation},${p.height},${interp},N`, - fdField(p.content), - ].filter(Boolean).join(''); - }, - - PropertiesPanel: ({ obj, onChange }) => { - const t = useT(); - const p = obj.props; - return ( -
-
- - onChange({ content: filterContent(e.target.value, ean13Spec) })} - /> -
- - onChange({ height })} - /> - - onChange({ moduleWidth })} - /> - - - - onChange({ rotation })} /> -
- ); + return `^BE${p.rotation},${p.height},${interp},N`; }, -}; +}); diff --git a/src/registry/ean8.tsx b/src/registry/ean8.tsx index 91e5187..290b3a9 100644 --- a/src/registry/ean8.tsx +++ b/src/registry/ean8.tsx @@ -6,7 +6,7 @@ export const ean8 = createBarcode1D({ icon: 'E8', defaultContent: '1234567', hasCheckDigit: false, - localeKey: 'ean8', + locale: (t) => t.registry.ean8, group: 'code-1d', contentSpec: { charset: '0-9', maxLength: 7 }, zplCommand: (p) => { diff --git a/src/registry/industrial2of5.tsx b/src/registry/industrial2of5.tsx index 6fac1cd..f109d09 100644 --- a/src/registry/industrial2of5.tsx +++ b/src/registry/industrial2of5.tsx @@ -6,7 +6,7 @@ export const industrial2of5 = createBarcode1D({ icon: "I25", defaultContent: "12345678", hasCheckDigit: false, - localeKey: "industrial2of5", + locale: (t) => t.registry.industrial2of5, group: 'code-1d', contentSpec: { charset: '0-9' }, zplCommand: (p) => { diff --git a/src/registry/interleaved2of5.tsx b/src/registry/interleaved2of5.tsx index 6310ebc..696bde8 100644 --- a/src/registry/interleaved2of5.tsx +++ b/src/registry/interleaved2of5.tsx @@ -6,7 +6,7 @@ export const interleaved2of5 = createBarcode1D({ icon: 'I25', defaultContent: '12345678', hasCheckDigit: true, - localeKey: 'interleaved2of5', + locale: (t) => t.registry.interleaved2of5, group: 'code-1d', contentSpec: { charset: '0-9' }, zplCommand: (p) => { diff --git a/src/registry/logmars.tsx b/src/registry/logmars.tsx index cb94e95..020be80 100644 --- a/src/registry/logmars.tsx +++ b/src/registry/logmars.tsx @@ -6,7 +6,7 @@ export const logmars = createBarcode1D({ icon: "LOG", defaultContent: "LOGMARS1", hasCheckDigit: false, - localeKey: "logmars", + locale: (t) => t.registry.logmars, group: 'code-1d', contentSpec: { charset: '0-9A-Za-z\\-. $/+%' }, zplCommand: (p) => { diff --git a/src/registry/msi.tsx b/src/registry/msi.tsx index 9987655..606788d 100644 --- a/src/registry/msi.tsx +++ b/src/registry/msi.tsx @@ -6,7 +6,7 @@ export const msi = createBarcode1D({ icon: "MSI", defaultContent: "12345678", hasCheckDigit: true, - localeKey: "msi", + locale: (t) => t.registry.msi, group: 'code-1d', contentSpec: { charset: '0-9' }, // MSI standard specifies a 2:1 wide:narrow ratio, which bwip-js hardcodes diff --git a/src/registry/planet.tsx b/src/registry/planet.tsx index 01c4d57..d0bf400 100644 --- a/src/registry/planet.tsx +++ b/src/registry/planet.tsx @@ -6,7 +6,7 @@ export const planet = createBarcode1D({ icon: "✉P", defaultContent: "12345678901", hasCheckDigit: false, - localeKey: "planet", + locale: (t) => t.registry.planet, group: 'code-postal', contentSpec: { charset: '0-9' }, zplCommand: (p) => { diff --git a/src/registry/plessey.tsx b/src/registry/plessey.tsx index 02659c7..124805b 100644 --- a/src/registry/plessey.tsx +++ b/src/registry/plessey.tsx @@ -6,7 +6,7 @@ export const plessey = createBarcode1D({ icon: "PLS", defaultContent: "12345678", hasCheckDigit: true, - localeKey: "plessey", + locale: (t) => t.registry.plessey, group: 'code-1d', contentSpec: { charset: '0-9A-Fa-f' }, // Plessey uses 2:1 wide:narrow ratio (same as MSI); override ZPL default of 3.0 diff --git a/src/registry/postal.tsx b/src/registry/postal.tsx index b795a55..5b635e3 100644 --- a/src/registry/postal.tsx +++ b/src/registry/postal.tsx @@ -6,7 +6,7 @@ export const postal = createBarcode1D({ icon: "✉Z", defaultContent: "12345", hasCheckDigit: false, - localeKey: "postal", + locale: (t) => t.registry.postal, group: 'code-postal', contentSpec: { charset: '0-9' }, zplCommand: (p) => { diff --git a/src/registry/standard2of5.tsx b/src/registry/standard2of5.tsx index 2ed46b7..645917f 100644 --- a/src/registry/standard2of5.tsx +++ b/src/registry/standard2of5.tsx @@ -6,7 +6,7 @@ export const standard2of5 = createBarcode1D({ icon: "S25", defaultContent: "12345678", hasCheckDigit: false, - localeKey: "standard2of5", + locale: (t) => t.registry.standard2of5, group: 'code-1d', contentSpec: { charset: '0-9' }, zplCommand: (p) => { diff --git a/src/registry/upca.tsx b/src/registry/upca.tsx index 6b9f767..7686086 100644 --- a/src/registry/upca.tsx +++ b/src/registry/upca.tsx @@ -6,7 +6,7 @@ export const upca = createBarcode1D({ icon: 'UPC', defaultContent: '01234567890', hasCheckDigit: false, - localeKey: 'upca', + locale: (t) => t.registry.upca, group: 'code-1d', contentSpec: { charset: '0-9', maxLength: 11 }, zplCommand: (p) => { diff --git a/src/registry/upce.tsx b/src/registry/upce.tsx index 2ec6386..8e52d30 100644 --- a/src/registry/upce.tsx +++ b/src/registry/upce.tsx @@ -6,7 +6,7 @@ export const upce = createBarcode1D({ icon: 'UPE', defaultContent: '012345', hasCheckDigit: false, - localeKey: 'upce', + locale: (t) => t.registry.upce, group: 'code-1d', contentSpec: { charset: '0-9', maxLength: 6 }, zplCommand: (p) => { diff --git a/src/test/testModels.ts b/src/test/testModels.ts index ed1c5b5..ea383d7 100644 --- a/src/test/testModels.ts +++ b/src/test/testModels.ts @@ -78,6 +78,7 @@ export const testModels: Record = { height: 100, moduleWidth: 2, printInterpretation: false, + checkDigit: false, rotation: "N", }, }, @@ -438,7 +439,7 @@ export const testModels: Record = { x: 100, y: 100, rotation: 0, - props: { content: "123456789012", height: 100, moduleWidth: 2, printInterpretation: false, rotation: "R" }, + props: { content: "123456789012", height: 100, moduleWidth: 2, printInterpretation: false, checkDigit: false, rotation: "R" }, }, barcode_ean13_rot_B: { id: "rot9", @@ -446,6 +447,6 @@ export const testModels: Record = { x: 100, y: 100, rotation: 0, - props: { content: "123456789012", height: 100, moduleWidth: 2, printInterpretation: false, rotation: "B" }, + props: { content: "123456789012", height: 100, moduleWidth: 2, printInterpretation: false, checkDigit: false, rotation: "B" }, }, };