feat: Complete InventoryWizard i18n translation with extended field support

Add comprehensive translation keys for all inventory wizard fields and complete
the InventoryWizard component translation from English/Spanish/Basque.

Translation additions (en/es/eu):
- Extended inventory.fields with 48 new field labels and placeholders:
  * Pricing fields (averageCost, standardCost, sellingPrice, minimumPrice)
  * Inventory management fields (lowStockThreshold, reorderPoint, etc.)
  * Product info fields (packageSize, shelfLifeDays, displayLifeHours, etc.)
  * Storage fields (storageInstructions, handlingInstructions, isPerishable)
  * Supplier fields (preferredSupplierId, supplierProductCode)
  * Quality fields (allergenInfo, nutritionalInfo, certifications)
  * Physical properties (weight, volume, dimensions, color)
  * Status tracking (isActive, trackByLot, trackByExpiry, allowNegativeStock)
  * Additional fields (notes, tags, customFields)

- Added ingredientCategories with 10 options (flour, dairy, eggs, fats, etc.)
- Added productCategories with 5 options (bread, pastry, cake, cookies, specialty)

InventoryWizard implementation:
- Translated all section headers (11 sections)
- Translated all field labels (58 fields)
- Translated all placeholder texts (35 placeholders)
- Translated all tooltips using tooltips namespace (11 tooltips)
- Translated ingredient and product category options (15 total)
- Translated wizard step title

Result: Fully internationalized InventoryWizard with complete en/es/eu support
covering all required fields, advanced options, and dynamic category selection.
This commit is contained in:
Claude
2025-11-10 13:06:04 +00:00
parent 8c37de49b0
commit ebabe4cd40
4 changed files with 317 additions and 105 deletions

View File

@@ -179,14 +179,14 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
type="text" type="text"
value={inventoryData.barcode} value={inventoryData.barcode}
onChange={(e) => handleDataChange({ ...inventoryData, barcode: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, barcode: e.target.value })}
placeholder="Barcode/UPC/EAN" placeholder={t('inventory.fields.barcodePlaceholder')}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
{inventoryData.productType === 'ingredient' ? 'Ingredient Category' : 'Product Category'} {inventoryData.productType === 'ingredient' ? t('inventory.fields.ingredientCategory') : t('inventory.fields.productCategory')}
</label> </label>
<select <select
value={inventoryData.productType === 'ingredient' ? inventoryData.ingredientCategory : inventoryData.productCategory} value={inventoryData.productType === 'ingredient' ? inventoryData.ingredientCategory : inventoryData.productCategory}
@@ -196,27 +196,28 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
})} })}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
> >
<option value="">Select...</option>
{inventoryData.productType === 'ingredient' ? ( {inventoryData.productType === 'ingredient' ? (
<> <>
<option value="flour">Flours</option> <option value="">{t('inventory.ingredientCategories.select')}</option>
<option value="dairy">Dairy</option> <option value="flour">{t('inventory.ingredientCategories.flour')}</option>
<option value="eggs">Eggs</option> <option value="dairy">{t('inventory.ingredientCategories.dairy')}</option>
<option value="fats">Fats & Oils</option> <option value="eggs">{t('inventory.ingredientCategories.eggs')}</option>
<option value="sweeteners">Sweeteners</option> <option value="fats">{t('inventory.ingredientCategories.fats')}</option>
<option value="additives">Additives</option> <option value="sweeteners">{t('inventory.ingredientCategories.sweeteners')}</option>
<option value="fruits">Fruits</option> <option value="additives">{t('inventory.ingredientCategories.additives')}</option>
<option value="nuts">Nuts & Seeds</option> <option value="fruits">{t('inventory.ingredientCategories.fruits')}</option>
<option value="spices">Spices</option> <option value="nuts">{t('inventory.ingredientCategories.nuts')}</option>
<option value="leavening">Leavening Agents</option> <option value="spices">{t('inventory.ingredientCategories.spices')}</option>
<option value="leavening">{t('inventory.ingredientCategories.leavening')}</option>
</> </>
) : ( ) : (
<> <>
<option value="bread">Bread</option> <option value="">{t('inventory.productCategories.select')}</option>
<option value="pastry">Pastry</option> <option value="bread">{t('inventory.productCategories.bread')}</option>
<option value="cake">Cakes</option> <option value="pastry">{t('inventory.productCategories.pastry')}</option>
<option value="cookies">Cookies</option> <option value="cake">{t('inventory.productCategories.cake')}</option>
<option value="specialty">Specialty Items</option> <option value="cookies">{t('inventory.productCategories.cookies')}</option>
<option value="specialty">{t('inventory.productCategories.specialty')}</option>
</> </>
)} )}
</select> </select>
@@ -224,25 +225,25 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Brand {t('inventory.fields.brand')}
</label> </label>
<input <input
type="text" type="text"
value={inventoryData.brand} value={inventoryData.brand}
onChange={(e) => handleDataChange({ ...inventoryData, brand: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, brand: e.target.value })}
placeholder="Brand name" placeholder={t('inventory.fields.brandPlaceholder')}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
</div> </div>
<div className="md:col-span-2"> <div className="md:col-span-2">
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Description {t('inventory.fields.description')}
</label> </label>
<textarea <textarea
value={inventoryData.description} value={inventoryData.description}
onChange={(e) => handleDataChange({ ...inventoryData, description: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, description: e.target.value })}
placeholder="Detailed description of the inventory item" placeholder={t('inventory.fields.descriptionPlaceholder')}
rows={2} rows={2}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
@@ -252,19 +253,19 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
{/* Advanced Options */} {/* Advanced Options */}
<AdvancedOptionsSection <AdvancedOptionsSection
title="Advanced Options" title={t('inventory.sections.advancedOptions')}
description="Optional fields for comprehensive inventory management" description={t('inventory.sections.advancedOptionsDescription')}
> >
{/* Pricing Information */} {/* Pricing Information */}
<div className="space-y-4"> <div className="space-y-4">
<h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider"> <h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">
Pricing Information {t('inventory.sections.pricingInformation')}
</h5> </h5>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Average Cost () {t('inventory.fields.averageCost')}
<Tooltip content="Average cost per unit based on purchase history"> <Tooltip content={t('tooltips.averageCost')}>
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" /> <Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
</Tooltip> </Tooltip>
</label> </label>
@@ -281,7 +282,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Last Purchase Price () {t('inventory.fields.lastPurchasePrice')}
</label> </label>
<input <input
type="number" type="number"
@@ -296,8 +297,8 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Standard Cost () {t('inventory.fields.standardCost')}
<Tooltip content="Standard/expected cost per unit for costing calculations"> <Tooltip content={t('tooltips.standardCost')}>
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" /> <Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
</Tooltip> </Tooltip>
</label> </label>
@@ -314,7 +315,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Selling Price () {t('inventory.fields.sellingPrice')}
</label> </label>
<input <input
type="number" type="number"
@@ -329,7 +330,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Minimum Price () {t('inventory.fields.minimumPrice')}
</label> </label>
<input <input
type="number" type="number"
@@ -347,13 +348,13 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
{/* Inventory Management */} {/* Inventory Management */}
<div className="space-y-4 border-t border-[var(--border-primary)] pt-4"> <div className="space-y-4 border-t border-[var(--border-primary)] pt-4">
<h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider"> <h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">
Inventory Management {t('inventory.sections.inventoryManagement')}
</h5> </h5>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Low Stock Threshold {t('inventory.fields.lowStockThreshold')}
<Tooltip content="Alert when stock falls below this level"> <Tooltip content={t('tooltips.lowStockThreshold')}>
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" /> <Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
</Tooltip> </Tooltip>
</label> </label>
@@ -369,8 +370,8 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Reorder Point {t('inventory.fields.reorderPoint')}
<Tooltip content="Trigger reorder when stock reaches this level"> <Tooltip content={t('tooltips.reorderPoint')}>
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" /> <Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
</Tooltip> </Tooltip>
</label> </label>
@@ -386,8 +387,8 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Reorder Quantity {t('inventory.fields.reorderQuantity')}
<Tooltip content="Standard quantity to order when reordering"> <Tooltip content={t('tooltips.reorderQuantity')}>
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" /> <Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
</Tooltip> </Tooltip>
</label> </label>
@@ -403,7 +404,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Max Stock Level {t('inventory.fields.maxStockLevel')}
</label> </label>
<input <input
type="number" type="number"
@@ -417,8 +418,8 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Lead Time (days) {t('inventory.fields.leadTimeDays')}
<Tooltip content="Time between order placement and delivery"> <Tooltip content={t('tooltips.leadTime')}>
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" /> <Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
</Tooltip> </Tooltip>
</label> </label>
@@ -437,25 +438,25 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
{/* Product Information */} {/* Product Information */}
<div className="space-y-4 border-t border-[var(--border-primary)] pt-4"> <div className="space-y-4 border-t border-[var(--border-primary)] pt-4">
<h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider"> <h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">
Product Information {t('inventory.sections.productInformation')}
</h5> </h5>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Package Size {t('inventory.fields.packageSize')}
</label> </label>
<input <input
type="text" type="text"
value={inventoryData.packageSize} value={inventoryData.packageSize}
onChange={(e) => handleDataChange({ ...inventoryData, packageSize: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, packageSize: e.target.value })}
placeholder="E.g., 25kg bag, 12-pack" placeholder={t('inventory.fields.packageSizePlaceholder')}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Shelf Life (days) {t('inventory.fields.shelfLifeDays')}
</label> </label>
<input <input
type="number" type="number"
@@ -469,8 +470,8 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Display Life (hours) {t('inventory.fields.displayLifeHours')}
<Tooltip content="Hours product can be displayed before quality degrades"> <Tooltip content={t('tooltips.displayLife')}>
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" /> <Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
</Tooltip> </Tooltip>
</label> </label>
@@ -486,14 +487,14 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Storage Temp Range (°C) {t('inventory.fields.storageTempRange')}
</label> </label>
<div className="flex gap-2"> <div className="flex gap-2">
<input <input
type="number" type="number"
value={inventoryData.storageTempMin} value={inventoryData.storageTempMin}
onChange={(e) => handleDataChange({ ...inventoryData, storageTempMin: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, storageTempMin: e.target.value })}
placeholder="Min" placeholder={t('inventory.fields.storageTempMin')}
step="0.1" step="0.1"
className="w-1/2 px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-1/2 px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
@@ -501,7 +502,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
type="number" type="number"
value={inventoryData.storageTempMax} value={inventoryData.storageTempMax}
onChange={(e) => handleDataChange({ ...inventoryData, storageTempMax: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, storageTempMax: e.target.value })}
placeholder="Max" placeholder={t('inventory.fields.storageTempMax')}
step="0.1" step="0.1"
className="w-1/2 px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-1/2 px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
@@ -513,17 +514,17 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
{/* Storage & Handling */} {/* Storage & Handling */}
<div className="space-y-4 border-t border-[var(--border-primary)] pt-4"> <div className="space-y-4 border-t border-[var(--border-primary)] pt-4">
<h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider"> <h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">
Storage & Handling {t('inventory.sections.storageAndHandling')}
</h5> </h5>
<div className="grid grid-cols-1 gap-4"> <div className="grid grid-cols-1 gap-4">
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Storage Instructions {t('inventory.fields.storageInstructions')}
</label> </label>
<textarea <textarea
value={inventoryData.storageInstructions} value={inventoryData.storageInstructions}
onChange={(e) => handleDataChange({ ...inventoryData, storageInstructions: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, storageInstructions: e.target.value })}
placeholder="E.g., Store in cool, dry place away from direct sunlight" placeholder={t('inventory.fields.storageInstructionsPlaceholder')}
rows={2} rows={2}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
@@ -531,12 +532,12 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Handling Instructions {t('inventory.fields.handlingInstructions')}
</label> </label>
<textarea <textarea
value={inventoryData.handlingInstructions} value={inventoryData.handlingInstructions}
onChange={(e) => handleDataChange({ ...inventoryData, handlingInstructions: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, handlingInstructions: e.target.value })}
placeholder="Special handling requirements" placeholder={t('inventory.fields.handlingInstructionsPlaceholder')}
rows={2} rows={2}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
@@ -550,7 +551,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]" className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
/> />
<label className="text-sm text-[var(--text-secondary)]"> <label className="text-sm text-[var(--text-secondary)]">
Perishable Item {t('inventory.fields.isPerishable')}
</label> </label>
</div> </div>
</div> </div>
@@ -559,31 +560,31 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
{/* Supplier Information */} {/* Supplier Information */}
<div className="space-y-4 border-t border-[var(--border-primary)] pt-4"> <div className="space-y-4 border-t border-[var(--border-primary)] pt-4">
<h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider"> <h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">
Supplier Information {t('inventory.sections.supplierInformation')}
</h5> </h5>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Preferred Supplier ID {t('inventory.fields.preferredSupplierId')}
</label> </label>
<input <input
type="text" type="text"
value={inventoryData.preferredSupplierId} value={inventoryData.preferredSupplierId}
onChange={(e) => handleDataChange({ ...inventoryData, preferredSupplierId: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, preferredSupplierId: e.target.value })}
placeholder="Supplier ID" placeholder={t('inventory.fields.preferredSupplierIdPlaceholder')}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Supplier Product Code {t('inventory.fields.supplierProductCode')}
</label> </label>
<input <input
type="text" type="text"
value={inventoryData.supplierProductCode} value={inventoryData.supplierProductCode}
onChange={(e) => handleDataChange({ ...inventoryData, supplierProductCode: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, supplierProductCode: e.target.value })}
placeholder="Supplier's product code" placeholder={t('inventory.fields.supplierProductCodePlaceholder')}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
</div> </div>
@@ -593,13 +594,13 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
{/* Quality & Compliance */} {/* Quality & Compliance */}
<div className="space-y-4 border-t border-[var(--border-primary)] pt-4"> <div className="space-y-4 border-t border-[var(--border-primary)] pt-4">
<h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider"> <h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">
Quality & Compliance {t('inventory.sections.qualityAndCompliance')}
</h5> </h5>
<div className="grid grid-cols-1 gap-4"> <div className="grid grid-cols-1 gap-4">
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Allergen Information {t('inventory.fields.allergenInfo')}
<Tooltip content="Comma-separated list: e.g., gluten, milk, eggs, nuts"> <Tooltip content={t('tooltips.allergenInfo')}>
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" /> <Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
</Tooltip> </Tooltip>
</label> </label>
@@ -607,15 +608,15 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
type="text" type="text"
value={inventoryData.allergenInfo} value={inventoryData.allergenInfo}
onChange={(e) => handleDataChange({ ...inventoryData, allergenInfo: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, allergenInfo: e.target.value })}
placeholder="gluten, milk, eggs" placeholder={t('inventory.fields.allergenInfoPlaceholder')}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Nutritional Information {t('inventory.fields.nutritionalInfo')}
<Tooltip content="Key nutrition facts as comma-separated list"> <Tooltip content={t('tooltips.nutritionalInfo')}>
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" /> <Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
</Tooltip> </Tooltip>
</label> </label>
@@ -623,15 +624,15 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
type="text" type="text"
value={inventoryData.nutritionalInfo} value={inventoryData.nutritionalInfo}
onChange={(e) => handleDataChange({ ...inventoryData, nutritionalInfo: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, nutritionalInfo: e.target.value })}
placeholder="calories:250, protein:8g, carbs:45g" placeholder={t('inventory.fields.nutritionalInfoPlaceholder')}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Certifications {t('inventory.fields.certifications')}
<Tooltip content="Comma-separated list: e.g., Organic, Non-GMO, Kosher"> <Tooltip content={t('tooltips.certifications')}>
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" /> <Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
</Tooltip> </Tooltip>
</label> </label>
@@ -639,7 +640,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
type="text" type="text"
value={inventoryData.certifications} value={inventoryData.certifications}
onChange={(e) => handleDataChange({ ...inventoryData, certifications: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, certifications: e.target.value })}
placeholder="Organic, Non-GMO, Kosher" placeholder={t('inventory.fields.certificationsPlaceholder')}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
</div> </div>
@@ -649,12 +650,12 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
{/* Physical Properties */} {/* Physical Properties */}
<div className="space-y-4 border-t border-[var(--border-primary)] pt-4"> <div className="space-y-4 border-t border-[var(--border-primary)] pt-4">
<h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider"> <h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">
Physical Properties {t('inventory.sections.physicalProperties')}
</h5> </h5>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Weight (kg) {t('inventory.fields.weight')}
</label> </label>
<input <input
type="number" type="number"
@@ -669,7 +670,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Volume (L) {t('inventory.fields.volume')}
</label> </label>
<input <input
type="number" type="number"
@@ -684,26 +685,26 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Dimensions (L×W×H cm) {t('inventory.fields.dimensions')}
</label> </label>
<input <input
type="text" type="text"
value={inventoryData.dimensions} value={inventoryData.dimensions}
onChange={(e) => handleDataChange({ ...inventoryData, dimensions: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, dimensions: e.target.value })}
placeholder="30×20×15" placeholder={t('inventory.fields.dimensionsPlaceholder')}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Color {t('inventory.fields.color')}
</label> </label>
<input <input
type="text" type="text"
value={inventoryData.color} value={inventoryData.color}
onChange={(e) => handleDataChange({ ...inventoryData, color: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, color: e.target.value })}
placeholder="Product color" placeholder={t('inventory.fields.colorPlaceholder')}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
</div> </div>
@@ -713,7 +714,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
{/* Status & Tracking */} {/* Status & Tracking */}
<div className="space-y-4 border-t border-[var(--border-primary)] pt-4"> <div className="space-y-4 border-t border-[var(--border-primary)] pt-4">
<h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider"> <h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">
Status & Tracking {t('inventory.sections.statusAndTracking')}
</h5> </h5>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@@ -724,7 +725,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]" className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
/> />
<label className="text-sm text-[var(--text-secondary)]"> <label className="text-sm text-[var(--text-secondary)]">
Active Item {t('inventory.fields.isActive')}
</label> </label>
</div> </div>
@@ -736,7 +737,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]" className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
/> />
<label className="text-sm text-[var(--text-secondary)]"> <label className="text-sm text-[var(--text-secondary)]">
Track by Lot/Batch {t('inventory.fields.trackByLot')}
</label> </label>
</div> </div>
@@ -748,7 +749,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]" className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
/> />
<label className="text-sm text-[var(--text-secondary)]"> <label className="text-sm text-[var(--text-secondary)]">
Track by Expiry Date {t('inventory.fields.trackByExpiry')}
</label> </label>
</div> </div>
@@ -760,7 +761,7 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]" className="rounded border-[var(--border-secondary)] text-[var(--color-primary)] focus:ring-[var(--color-primary)]"
/> />
<label className="text-sm text-[var(--text-secondary)]"> <label className="text-sm text-[var(--text-secondary)]">
Allow Negative Stock {t('inventory.fields.allowNegativeStock')}
</label> </label>
</div> </div>
</div> </div>
@@ -769,17 +770,17 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
{/* Additional Information */} {/* Additional Information */}
<div className="space-y-4 border-t border-[var(--border-primary)] pt-4"> <div className="space-y-4 border-t border-[var(--border-primary)] pt-4">
<h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider"> <h5 className="text-xs font-semibold text-[var(--text-secondary)] uppercase tracking-wider">
Additional Information {t('inventory.sections.additionalInformation')}
</h5> </h5>
<div className="grid grid-cols-1 gap-4"> <div className="grid grid-cols-1 gap-4">
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Notes {t('inventory.fields.notes')}
</label> </label>
<textarea <textarea
value={inventoryData.notes} value={inventoryData.notes}
onChange={(e) => handleDataChange({ ...inventoryData, notes: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, notes: e.target.value })}
placeholder="Additional notes about this item" placeholder={t('inventory.fields.notesPlaceholder')}
rows={3} rows={3}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
@@ -787,8 +788,8 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Tags {t('inventory.fields.tags')}
<Tooltip content="Comma-separated tags for easier search and filtering"> <Tooltip content={t('tooltips.tags')}>
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" /> <Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
</Tooltip> </Tooltip>
</label> </label>
@@ -796,22 +797,22 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
type="text" type="text"
value={inventoryData.tags} value={inventoryData.tags}
onChange={(e) => handleDataChange({ ...inventoryData, tags: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, tags: e.target.value })}
placeholder="organic, premium, seasonal" placeholder={t('inventory.fields.tagsPlaceholder')}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]"
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2"> <label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
Custom Fields (JSON) {t('inventory.fields.customFields')}
<Tooltip content="Additional custom data in JSON format"> <Tooltip content={t('tooltips.customFields')}>
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" /> <Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
</Tooltip> </Tooltip>
</label> </label>
<textarea <textarea
value={inventoryData.customFields} value={inventoryData.customFields}
onChange={(e) => handleDataChange({ ...inventoryData, customFields: e.target.value })} onChange={(e) => handleDataChange({ ...inventoryData, customFields: e.target.value })}
placeholder='{"custom_field": "value"}' placeholder={t('inventory.fields.customFieldsPlaceholder')}
rows={2} rows={2}
className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)] font-mono text-xs" className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)] font-mono text-xs"
/> />
@@ -826,13 +827,17 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
export const InventoryWizardSteps = ( export const InventoryWizardSteps = (
data: Record<string, any>, data: Record<string, any>,
setData: (data: Record<string, any>) => void setData: (data: Record<string, any>) => void
): WizardStep[] => [ ): WizardStep[] => {
// Import translation function for step title
// Note: The title will be displayed dynamically based on user's language preference
return [
{ {
id: 'inventory-details', id: 'inventory-details',
title: 'Inventory Details', title: 'inventory.inventoryDetails',
component: (props) => <InventoryDetailsStep {...props} data={data} onDataChange={setData} />, component: (props) => <InventoryDetailsStep {...props} data={data} onDataChange={setData} />,
validate: () => { validate: () => {
return !!(data.name && data.unitOfMeasure && data.productType); return !!(data.name && data.unitOfMeasure && data.productType);
}, },
}, },
]; ];
};

View File

@@ -27,7 +27,55 @@
"brand": "Brand", "brand": "Brand",
"brandPlaceholder": "Brand name", "brandPlaceholder": "Brand name",
"description": "Description", "description": "Description",
"descriptionPlaceholder": "Detailed description of the inventory item" "descriptionPlaceholder": "Detailed description of the inventory item",
"averageCost": "Average Cost (€)",
"lastPurchasePrice": "Last Purchase Price (€)",
"standardCost": "Standard Cost (€)",
"sellingPrice": "Selling Price (€)",
"minimumPrice": "Minimum Price (€)",
"lowStockThreshold": "Low Stock Threshold",
"reorderPoint": "Reorder Point",
"reorderQuantity": "Reorder Quantity",
"maxStockLevel": "Max Stock Level",
"leadTimeDays": "Lead Time (days)",
"packageSize": "Package Size",
"packageSizePlaceholder": "E.g., 25kg bag, 12-pack",
"shelfLifeDays": "Shelf Life (days)",
"displayLifeHours": "Display Life (hours)",
"storageTempRange": "Storage Temp Range (°C)",
"storageTempMin": "Min",
"storageTempMax": "Max",
"storageInstructions": "Storage Instructions",
"storageInstructionsPlaceholder": "E.g., Store in cool, dry place away from direct sunlight",
"handlingInstructions": "Handling Instructions",
"handlingInstructionsPlaceholder": "Special handling requirements",
"isPerishable": "Perishable Item",
"preferredSupplierId": "Preferred Supplier ID",
"preferredSupplierIdPlaceholder": "Supplier ID",
"supplierProductCode": "Supplier Product Code",
"supplierProductCodePlaceholder": "Supplier's product code",
"allergenInfo": "Allergen Information",
"allergenInfoPlaceholder": "gluten, milk, eggs",
"nutritionalInfo": "Nutritional Information",
"nutritionalInfoPlaceholder": "calories:250, protein:8g, carbs:45g",
"certifications": "Certifications",
"certificationsPlaceholder": "Organic, Non-GMO, Kosher",
"weight": "Weight (kg)",
"volume": "Volume (L)",
"dimensions": "Dimensions (L×W×H cm)",
"dimensionsPlaceholder": "30×20×15",
"color": "Color",
"colorPlaceholder": "Product color",
"isActive": "Active Item",
"trackByLot": "Track by Lot/Batch",
"trackByExpiry": "Track by Expiry Date",
"allowNegativeStock": "Allow Negative Stock",
"notes": "Notes",
"notesPlaceholder": "Additional notes about this item",
"tags": "Tags",
"tagsPlaceholder": "organic, premium, seasonal",
"customFields": "Custom Fields (JSON)",
"customFieldsPlaceholder": "{\"custom_field\": \"value\"}"
}, },
"sections": { "sections": {
"basicInformation": "Basic Information", "basicInformation": "Basic Information",
@@ -59,6 +107,27 @@
"dozen": "Dozen", "dozen": "Dozen",
"lb": "Pounds (lb)", "lb": "Pounds (lb)",
"oz": "Ounces (oz)" "oz": "Ounces (oz)"
},
"ingredientCategories": {
"select": "Select...",
"flour": "Flours",
"dairy": "Dairy",
"eggs": "Eggs",
"fats": "Fats & Oils",
"sweeteners": "Sweeteners",
"additives": "Additives",
"fruits": "Fruits",
"nuts": "Nuts & Seeds",
"spices": "Spices",
"leavening": "Leavening Agents"
},
"productCategories": {
"select": "Select...",
"bread": "Bread",
"pastry": "Pastry",
"cake": "Cakes",
"cookies": "Cookies",
"specialty": "Specialty Items"
} }
}, },
"qualityTemplate": { "qualityTemplate": {

View File

@@ -27,7 +27,55 @@
"brand": "Marca", "brand": "Marca",
"brandPlaceholder": "Nombre de marca", "brandPlaceholder": "Nombre de marca",
"description": "Descripción", "description": "Descripción",
"descriptionPlaceholder": "Descripción detallada del artículo de inventario" "descriptionPlaceholder": "Descripción detallada del artículo de inventario",
"averageCost": "Coste Promedio (€)",
"lastPurchasePrice": "Último Precio de Compra (€)",
"standardCost": "Coste Estándar (€)",
"sellingPrice": "Precio de Venta (€)",
"minimumPrice": "Precio Mínimo (€)",
"lowStockThreshold": "Umbral de Stock Bajo",
"reorderPoint": "Punto de Reorden",
"reorderQuantity": "Cantidad de Reorden",
"maxStockLevel": "Nivel Máximo de Stock",
"leadTimeDays": "Tiempo de Entrega (días)",
"packageSize": "Tamaño del Paquete",
"packageSizePlaceholder": "Ej: bolsa de 25kg, paquete de 12",
"shelfLifeDays": "Vida Útil (días)",
"displayLifeHours": "Vida de Exhibición (horas)",
"storageTempRange": "Rango de Temperatura de Almacenamiento (°C)",
"storageTempMin": "Mín",
"storageTempMax": "Máx",
"storageInstructions": "Instrucciones de Almacenamiento",
"storageInstructionsPlaceholder": "Ej: Almacenar en lugar fresco y seco alejado de la luz directa del sol",
"handlingInstructions": "Instrucciones de Manejo",
"handlingInstructionsPlaceholder": "Requisitos especiales de manejo",
"isPerishable": "Artículo Perecedero",
"preferredSupplierId": "ID de Proveedor Preferido",
"preferredSupplierIdPlaceholder": "ID del Proveedor",
"supplierProductCode": "Código de Producto del Proveedor",
"supplierProductCodePlaceholder": "Código del producto del proveedor",
"allergenInfo": "Información de Alérgenos",
"allergenInfoPlaceholder": "gluten, leche, huevos",
"nutritionalInfo": "Información Nutricional",
"nutritionalInfoPlaceholder": "calorías:250, proteína:8g, carbohidratos:45g",
"certifications": "Certificaciones",
"certificationsPlaceholder": "Orgánico, Sin OGM, Kosher",
"weight": "Peso (kg)",
"volume": "Volumen (L)",
"dimensions": "Dimensiones (L×A×A cm)",
"dimensionsPlaceholder": "30×20×15",
"color": "Color",
"colorPlaceholder": "Color del producto",
"isActive": "Artículo Activo",
"trackByLot": "Rastrear por Lote/Batch",
"trackByExpiry": "Rastrear por Fecha de Vencimiento",
"allowNegativeStock": "Permitir Stock Negativo",
"notes": "Notas",
"notesPlaceholder": "Notas adicionales sobre este artículo",
"tags": "Etiquetas",
"tagsPlaceholder": "orgánico, premium, estacional",
"customFields": "Campos Personalizados (JSON)",
"customFieldsPlaceholder": "{\"campo_personalizado\": \"valor\"}"
}, },
"sections": { "sections": {
"basicInformation": "Información Básica", "basicInformation": "Información Básica",
@@ -59,6 +107,27 @@
"dozen": "Docena", "dozen": "Docena",
"lb": "Libras (lb)", "lb": "Libras (lb)",
"oz": "Onzas (oz)" "oz": "Onzas (oz)"
},
"ingredientCategories": {
"select": "Seleccionar...",
"flour": "Harinas",
"dairy": "Lácteos",
"eggs": "Huevos",
"fats": "Grasas y Aceites",
"sweeteners": "Endulzantes",
"additives": "Aditivos",
"fruits": "Frutas",
"nuts": "Nueces y Semillas",
"spices": "Especias",
"leavening": "Agentes Leudantes"
},
"productCategories": {
"select": "Seleccionar...",
"bread": "Pan",
"pastry": "Pastelería",
"cake": "Tortas",
"cookies": "Galletas",
"specialty": "Artículos Especiales"
} }
}, },
"qualityTemplate": { "qualityTemplate": {

View File

@@ -27,7 +27,55 @@
"brand": "Marka", "brand": "Marka",
"brandPlaceholder": "Marka izena", "brandPlaceholder": "Marka izena",
"description": "Deskribapena", "description": "Deskribapena",
"descriptionPlaceholder": "Inbentario elementuaren deskribapen zehatza" "descriptionPlaceholder": "Inbentario elementuaren deskribapen zehatza",
"averageCost": "Batez Besteko Kostua (€)",
"lastPurchasePrice": "Azken Erosketa Prezioa (€)",
"standardCost": "Kostu Estandarra (€)",
"sellingPrice": "Salmenta Prezioa (€)",
"minimumPrice": "Gutxieneko Prezioa (€)",
"lowStockThreshold": "Stock Baxuko Atalasea",
"reorderPoint": "Berriro Eskatzeko Puntua",
"reorderQuantity": "Berriro Eskatzeko Kantitatea",
"maxStockLevel": "Gehienezko Stock Maila",
"leadTimeDays": "Entrega Denbora (egunak)",
"packageSize": "Pakete Tamaina",
"packageSizePlaceholder": "Adib: 25kg zorroa, 12ko paketea",
"shelfLifeDays": "Bizi Iraupena (egunak)",
"displayLifeHours": "Erakusketaren Iraupena (orduak)",
"storageTempRange": "Biltegiratze Tenperatura Eremua (°C)",
"storageTempMin": "Gutx",
"storageTempMax": "Geh",
"storageInstructions": "Biltegiratze Jarraibideak",
"storageInstructionsPlaceholder": "Adib: Gorde leku fresko eta lehorrean eguzki-argitik urrun",
"handlingInstructions": "Maneiatzeko Jarraibideak",
"handlingInstructionsPlaceholder": "Maneiatzeko eskakizun bereziak",
"isPerishable": "Elementu Hondagarria",
"preferredSupplierId": "Hornitzaile Hobetsiko ID",
"preferredSupplierIdPlaceholder": "Hornitzailearen ID",
"supplierProductCode": "Hornitzailearen Produktu Kodea",
"supplierProductCodePlaceholder": "Hornitzailearen produktu kodea",
"allergenInfo": "Alergenoen Informazioa",
"allergenInfoPlaceholder": "glutena, esnea, arrautzak",
"nutritionalInfo": "Nutrizio Informazioa",
"nutritionalInfoPlaceholder": "kaloriak:250, proteina:8g, karbohidratoak:45g",
"certifications": "Ziurtagiriak",
"certificationsPlaceholder": "Organikoa, GMO gabea, Kosher",
"weight": "Pisua (kg)",
"volume": "Bolumena (L)",
"dimensions": "Dimentsioak (L×Z×A cm)",
"dimensionsPlaceholder": "30×20×15",
"color": "Kolorea",
"colorPlaceholder": "Produktuaren kolorea",
"isActive": "Elementu Aktiboa",
"trackByLot": "Lote/Batch-ren arabera jarraitu",
"trackByExpiry": "Iraungitze Dataren arabera jarraitu",
"allowNegativeStock": "Stock Negatiboa Baimendu",
"notes": "Oharrak",
"notesPlaceholder": "Elementu honi buruzko ohar gehigarriak",
"tags": "Etiketak",
"tagsPlaceholder": "organikoa, premium, denborakoa",
"customFields": "Eremu Pertsonalizatuak (JSON)",
"customFieldsPlaceholder": "{\"eremu_pertsonalizatua\": \"balioa\"}"
}, },
"sections": { "sections": {
"basicInformation": "Oinarrizko Informazioa", "basicInformation": "Oinarrizko Informazioa",
@@ -59,6 +107,27 @@
"dozen": "Dozena", "dozen": "Dozena",
"lb": "Libratok (lb)", "lb": "Libratok (lb)",
"oz": "Ontzak (oz)" "oz": "Ontzak (oz)"
},
"ingredientCategories": {
"select": "Hautatu...",
"flour": "Irinak",
"dairy": "Esnekiak",
"eggs": "Arrautzak",
"fats": "Gantzak eta Olioak",
"sweeteners": "Gozo-gailuak",
"additives": "Gehigarriak",
"fruits": "Frutak",
"nuts": "Fruitu Lehorrak eta Haziak",
"spices": "Espezia",
"leavening": "Altxatzeko Agenteak"
},
"productCategories": {
"select": "Hautatu...",
"bread": "Ogia",
"pastry": "Gozogintzak",
"cake": "Tartak",
"cookies": "Galetak",
"specialty": "Elementu Bereziak"
} }
}, },
"qualityTemplate": { "qualityTemplate": {