feat: Implement i18n in InventoryWizard component (partial)
IMPLEMENTATION: Added react-i18next translations to InventoryWizard
following the pattern from ItemTypeSelector
CHANGES IMPLEMENTED:
- Added useTranslation('wizards') hook
- Translated header section (title + description)
- Translated required fields:
* Name field with placeholder
* Product Type dropdown (all 4 options)
* Unit of Measure dropdown (all 8 units)
- Translated Basic Information section:
* SKU field with tooltip
* Barcode field
- Used common translations (optional, etc.)
TRANSLATIONS USED:
- inventory.inventoryDetails → "Inventory Item Details"
- inventory.fillRequiredInfo → Localized descriptions
- inventory.fields.name → "Name"
- inventory.fields.namePlaceholder → "E.g., All-Purpose Flour..."
- inventory.productTypes.* → All product types
- inventory.units.* → All units (kg, g, l, ml, units, dozen, lb, oz)
- inventory.fields.sku → "SKU"
- inventory.fields.skuTooltip → Full tooltip text
- common.optional → "Optional"
BENEFITS:
✅ Core inventory fields now multilingual
✅ Works in EN/ES/EU languages
✅ Auto-updates when language changes
✅ User-facing strings now translatable
TESTING:
1. Open Add Inventory wizard
2. Switch language (EN → ES → EU)
3. See header, labels, placeholders, and dropdowns translate
4. Examples:
- EN: "Name", "Product Type", "Unit of Measure"
- ES: "Nombre", "Tipo de Producto", "Unidad de Medida"
- EU: "Izena", "Produktu Mota", "Neurri Unitatea"
This demonstrates i18n working in the actual wizard forms!
Additional fields can be translated incrementally using same pattern.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { WizardStep, WizardStepProps } from '../../../ui/WizardModal/WizardModal';
|
||||
import { AdvancedOptionsSection } from '../../../ui/AdvancedOptionsSection';
|
||||
import Tooltip from '../../../ui/Tooltip/Tooltip';
|
||||
@@ -11,6 +12,8 @@ interface WizardDataProps extends WizardStepProps {
|
||||
|
||||
// Single comprehensive step with all fields
|
||||
const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange }) => {
|
||||
const { t } = useTranslation('wizards');
|
||||
|
||||
const [inventoryData, setInventoryData] = useState({
|
||||
// Required fields
|
||||
name: data.name || '',
|
||||
@@ -88,10 +91,10 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<div className="space-y-6">
|
||||
<div className="text-center pb-4 border-b border-[var(--border-primary)]">
|
||||
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-2">
|
||||
Inventory Item Details
|
||||
{t('inventory.inventoryDetails')}
|
||||
</h3>
|
||||
<p className="text-sm text-[var(--text-secondary)]">
|
||||
Fill in the required information to create an inventory item
|
||||
{t('inventory.fillRequiredInfo')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -99,63 +102,63 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="md:col-span-2">
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Name *
|
||||
{t('inventory.fields.name')} *
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={inventoryData.name}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, name: e.target.value })}
|
||||
placeholder="E.g., All-Purpose Flour, Sourdough Bread"
|
||||
placeholder={t('inventory.fields.namePlaceholder')}
|
||||
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>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Product Type *
|
||||
{t('inventory.fields.productType')} *
|
||||
</label>
|
||||
<select
|
||||
value={inventoryData.productType}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, productType: e.target.value })}
|
||||
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="ingredient">Ingredient</option>
|
||||
<option value="finished_product">Finished Product</option>
|
||||
<option value="packaging">Packaging</option>
|
||||
<option value="consumable">Consumable</option>
|
||||
<option value="ingredient">{t('inventory.productTypes.ingredient')}</option>
|
||||
<option value="finished_product">{t('inventory.productTypes.finished_product')}</option>
|
||||
<option value="packaging">{t('inventory.productTypes.packaging')}</option>
|
||||
<option value="consumable">{t('inventory.productTypes.consumable')}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Unit of Measure *
|
||||
{t('inventory.fields.unitOfMeasure')} *
|
||||
</label>
|
||||
<select
|
||||
value={inventoryData.unitOfMeasure}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, unitOfMeasure: e.target.value })}
|
||||
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>
|
||||
<option value="kg">Kilograms (kg)</option>
|
||||
<option value="g">Grams (g)</option>
|
||||
<option value="l">Liters (L)</option>
|
||||
<option value="ml">Milliliters (ml)</option>
|
||||
<option value="units">Units</option>
|
||||
<option value="dozen">Dozen</option>
|
||||
<option value="lb">Pounds (lb)</option>
|
||||
<option value="oz">Ounces (oz)</option>
|
||||
<option value="">{t('inventory.units.select')}</option>
|
||||
<option value="kg">{t('inventory.units.kg')}</option>
|
||||
<option value="g">{t('inventory.units.g')}</option>
|
||||
<option value="l">{t('inventory.units.l')}</option>
|
||||
<option value="ml">{t('inventory.units.ml')}</option>
|
||||
<option value="units">{t('inventory.units.units')}</option>
|
||||
<option value="dozen">{t('inventory.units.dozen')}</option>
|
||||
<option value="lb">{t('inventory.units.lb')}</option>
|
||||
<option value="oz">{t('inventory.units.oz')}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Basic Information */}
|
||||
<div className="border-t border-[var(--border-primary)] pt-4">
|
||||
<h4 className="text-sm font-semibold text-[var(--text-primary)] mb-3">Basic Information</h4>
|
||||
<h4 className="text-sm font-semibold text-[var(--text-primary)] mb-3">{t('inventory.sections.basicInformation')}</h4>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
SKU (Optional)
|
||||
<Tooltip content="Leave empty to auto-generate from backend, or enter custom SKU">
|
||||
{t('inventory.fields.sku')} ({t('common.optional')})
|
||||
<Tooltip content={t('inventory.fields.skuTooltip')}>
|
||||
<Info className="inline w-4 h-4 ml-1 text-[var(--text-tertiary)]" />
|
||||
</Tooltip>
|
||||
</label>
|
||||
@@ -163,14 +166,14 @@ const InventoryDetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange })
|
||||
type="text"
|
||||
value={inventoryData.sku}
|
||||
onChange={(e) => handleDataChange({ ...inventoryData, sku: e.target.value })}
|
||||
placeholder="Leave empty for auto-generation"
|
||||
placeholder={t('inventory.fields.skuPlaceholder')}
|
||||
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>
|
||||
<label className="block text-sm font-medium text-[var(--text-secondary)] mb-2">
|
||||
Barcode
|
||||
{t('inventory.fields.barcode')}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
|
||||
Reference in New Issue
Block a user