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:
Claude
2025-11-10 12:56:19 +00:00
parent 680b97f6de
commit 8c37de49b0

View File

@@ -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"