diff --git a/frontend/src/components/domain/setup-wizard/steps/InventorySetupStep.tsx b/frontend/src/components/domain/setup-wizard/steps/InventorySetupStep.tsx index 5b835cb8..37555876 100644 --- a/frontend/src/components/domain/setup-wizard/steps/InventorySetupStep.tsx +++ b/frontend/src/components/domain/setup-wizard/steps/InventorySetupStep.tsx @@ -654,7 +654,7 @@ export const InventorySetupStep: React.FC = ({ onUpdate, onCompl )} {stock.batch_number && ( - Batch: {stock.batch_number} + {t('setup_wizard:inventory.batch_label', 'Batch')}: {stock.batch_number} )} - - - ))} + ); + })} )} + {/* Form-level error */} + {errors.form && ( +
+

{errors.form}

+
+ )} + {/* Add form */} {isAdding ? (
@@ -220,7 +330,7 @@ export const TeamSetupStep: React.FC = ({ onUpdate, onComplete, {errors.name &&

{errors.name}

} - {/* Email */} + {/* Email (Username) */}
+ {/* Password */} +
+ + setFormData({ ...formData, password: e.target.value })} + className={`w-full px-3 py-2 bg-[var(--bg-primary)] border ${errors.password ? 'border-[var(--color-error)]' : 'border-[var(--border-secondary)]'} rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] text-[var(--text-primary)]`} + placeholder={t('setup_wizard:team.placeholders.password', '••••••••')} + /> +

+ {t('setup_wizard:team.password_hint', 'Minimum 8 characters')} +

+ {errors.password &&

{errors.password}

} +
+ + {/* Confirm Password */} +
+ + setFormData({ ...formData, confirmPassword: e.target.value })} + className={`w-full px-3 py-2 bg-[var(--bg-primary)] border ${errors.confirmPassword ? 'border-[var(--color-error)]' : 'border-[var(--border-secondary)]'} rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] text-[var(--text-primary)]`} + placeholder={t('setup_wizard:team.placeholders.confirm_password', '••••••••')} + /> + {errors.confirmPassword &&

{errors.confirmPassword}

} +
+ + {/* Phone (Optional) */} +
+ + setFormData({ ...formData, phone: e.target.value })} + className="w-full px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] text-[var(--text-primary)]" + placeholder={t('setup_wizard:team.placeholders.phone', '+34 600 000 000')} + /> +
+ {/* Role */}
@@ -435,7 +435,7 @@ export const PublicHeader = forwardRef(({ -

+

{t('common:app.name', 'BakeWise')}

diff --git a/frontend/src/locales/en/blog.json b/frontend/src/locales/en/blog.json index ea67801d..3fafd328 100644 --- a/frontend/src/locales/en/blog.json +++ b/frontend/src/locales/en/blog.json @@ -11,7 +11,7 @@ }, "post": { "read_more": "Read full article", - "read_time": "{{time}} min" + "read_time": "{time} min" }, "categories": { "management": "Management", diff --git a/frontend/src/locales/en/common.json b/frontend/src/locales/en/common.json index f829c1eb..0401233a 100644 --- a/frontend/src/locales/en/common.json +++ b/frontend/src/locales/en/common.json @@ -351,12 +351,6 @@ "terms": "Terms", "cookies": "Cookies" }, - "social_follow": "Follow us on social media", - "social_labels": { - "twitter": "Twitter", - "linkedin": "LinkedIn", - "github": "GitHub" - }, "made_with_love": "Made with love in Madrid" }, "breadcrumbs": { diff --git a/frontend/src/locales/en/contact.json b/frontend/src/locales/en/contact.json new file mode 100644 index 00000000..8a4c5a36 --- /dev/null +++ b/frontend/src/locales/en/contact.json @@ -0,0 +1,83 @@ +{ + "hero": { + "badge": "Contact & Support", + "title": "We Are Here to", + "title_accent": "Help You", + "subtitle": "Have questions? Need help? Our team is ready to assist you" + }, + "methods": { + "title": "Multiple Ways to Contact", + "subtitle": "Choose the method that suits you best", + "email": { + "title": "Email", + "description": "support@panaderia-ia.com", + "detail": "Response in less than 4 hours" + }, + "phone": { + "title": "Phone", + "description": "+34 XXX XXX XXX", + "detail": "Monday to Friday: 10:00 - 19:00 CET" + }, + "office": { + "title": "Office", + "description": "Madrid, Spain", + "detail": "By appointment only" + } + }, + "form": { + "title": "Send Us a Message", + "subtitle": "Complete the form and we will get back to you as soon as possible", + "success": { + "title": "Message sent!", + "message": "We will get back to you soon." + }, + "error": { + "title": "Error sending.", + "message": "Please try again." + }, + "fields": { + "name": "Full Name", + "name_placeholder": "Your name", + "email": "Email", + "email_placeholder": "you@email.com", + "phone": "Phone (optional)", + "phone_placeholder": "+34 XXX XXX XXX", + "bakery_name": "Your Bakery Name (optional)", + "bakery_name_placeholder": "Example Bakery", + "type": "Query Type", + "type_options": { + "general": "General Inquiry", + "technical": "Technical Support", + "sales": "Commercial Information", + "feedback": "Feedback/Suggestions" + }, + "subject": "Subject", + "subject_placeholder": "How can we help you?", + "message": "Message", + "message_placeholder": "Tell us more about your inquiry or problem..." + }, + "submit": "Send Message", + "sending": "Sending...", + "privacy": "By sending this form, you accept our Privacy Policy", + "required_indicator": "*" + }, + "footer": { + "hours": { + "title": "Service Hours", + "email": { + "label": "Email:", + "detail": "24/7 (response in less than 4 hours during business hours)" + }, + "phone": { + "label": "Phone:", + "detail": "Monday to Friday: 10:00 - 19:00 CET (active clients only)" + } + }, + "faq": { + "title": "Looking for Quick Answers?", + "description": "Many questions are already answered in our Help Center and Documentation", + "help_center": "View Help Center →", + "docs": "Read Documentation →" + } + } +} \ No newline at end of file diff --git a/frontend/src/locales/en/dashboard.json b/frontend/src/locales/en/dashboard.json index beaaf8d7..2cf18144 100644 --- a/frontend/src/locales/en/dashboard.json +++ b/frontend/src/locales/en/dashboard.json @@ -163,7 +163,7 @@ "active_count": "{count} active alerts" }, "production": { - "scheduled_based_on": "Scheduled based on {{type}}", + "scheduled_based_on": "Scheduled based on {type}", "status": { "completed": "COMPLETED", "in_progress": "IN PROGRESS", @@ -198,26 +198,26 @@ }, "health": { "production_on_schedule": "Production on schedule", - "production_delayed": "{count} production batch{count, plural, one {} other {es}} delayed", - "production_late_to_start": "{count} batch{count, plural, one {} other {es}} not started on time", - "production_delayed_and_late": "{delayed} batch{delayed, plural, one {} other {es}} delayed and {late} not started on time", + "production_delayed": "{count} production batch{count, plural, one {} other {es} delayed}", + "production_late_to_start": "{count} batch{count, plural, one {} other {es} not started on time}", + "production_delayed_and_late": "{delayed} batch{delayed, plural, one {} other {es} delayed and {late} not started on time}", "production_issues": "{total} production issue{total, plural, one {} other {s}}", "production_ai_prevented": "AI prevented {count} production delay{count, plural, one {} other {s}}", "all_ingredients_in_stock": "All ingredients in stock", - "ingredients_out_of_stock": "{count} ingredient{count, plural, one {} other {s}} out of stock", + "ingredients_out_of_stock": "{count} ingredient{count, plural, one {} other {s} out of stock}", "inventory_ai_prevented": "AI prevented {count} inventory issue{count, plural, one {} other {s}}", "no_pending_approvals": "No pending approvals", - "approvals_awaiting": "{count} purchase order{count, plural, one {} other {s}} awaiting approval", - "procurement_ai_prevented": "AI created {count} purchase order{count, plural, one {} other {s}} automatically", + "approvals_awaiting": "{count} purchase order{count, plural, one {} other {s} awaiting approval}", + "procurement_ai_prevented": "AI created {count} purchase order{count, plural, one {} other {s} automatically}", "deliveries_on_track": "All deliveries on track", - "deliveries_overdue": "{count} deliver{count, plural, one {y} other {ies}} overdue", + "deliveries_overdue": "{count} deliver{count, plural, one {y} other {ies} overdue}", "deliveries_ai_prevented": "AI prevented {count} delivery issue{count, plural, one {} other {s}}", "deliveries_pending": "{count} pending deliver{count, plural, one {y} other {ies}}", "all_systems_operational": "All systems operational", "critical_issues": "{count} critical issue{count, plural, one {} other {s}}", "headline_green": "Your bakery is running smoothly", "headline_yellow_approvals": "Please review {count} pending approval{count, plural, one {} other {s}}", - "headline_yellow_alerts": "You have {count} alert{count, plural, one {} other {s}} needing attention", + "headline_yellow_alerts": "You have {count} alert{count, plural, one {} other {s} needing attention}", "headline_yellow_general": "Some items need your attention", "headline_red": "Critical issues require immediate action" }, @@ -287,7 +287,7 @@ "user_needed": "User Needed", "needs_review": "needs your review", "all_handled": "all handled by AI", - "prevented_badge": "{count} issue{{count, plural, one {} other {s}}} prevented", + "prevented_badge": "{count} issue{count, plural, one {} other {s} prevented}", "prevented_description": "AI proactively handled these before they became problems", "analyzed_title": "What I Analyzed", "actions_taken": "What I Did", @@ -400,7 +400,7 @@ "no_forecast_data": "No forecast data available", "no_performance_data": "No performance data available", "no_distribution_data": "No distribution data available", - "performance_based_on": "Performance based on {{metric}} over {{period}} days", + "performance_based_on": "Performance based on {metric} over {period} days", "ranking": "Ranking", "rank": "Rank", "outlet": "Outlet", @@ -585,7 +585,7 @@ "new_dashboard": { "system_status": { "title": "System Status", - "issues_requiring_action": "{count, plural, one {# issue} other {# issues}} requiring your action", + "issues_requiring_action": "{count, plural, one {# issue} other {# issues} requiring your action}", "all_clear": "All systems running smoothly", "never_run": "Never run", "action_needed_label": "action needed", @@ -602,7 +602,7 @@ }, "pending_purchases": { "title": "Pending Purchases", - "count": "{count, plural, one {# order} other {# orders}} awaiting approval", + "count": "{count, plural, one {# order} other {# orders} awaiting approval}", "no_pending": "No pending purchase orders", "all_clear": "No purchase orders pending approval", "po_number": "PO #{number}", @@ -613,10 +613,10 @@ "ai_reasoning": "AI created this PO because:", "reasoning": { "low_stock": "{ingredient} will run out in {days, plural, =0 {less than a day} one {# day} other {# days}}", - "low_stock_detailed": "{count, plural, one {# critical ingredient} other {# critical ingredients}} at risk: {products}. Earliest depletion in {days, plural, =0 {<1 day} one {1 day} other {# days}}, affecting {batches, plural, one {# batch} other {# batches}}. Potential loss: €{loss}", + "low_stock_detailed": "{count, plural, one {# critical ingredient} other {# critical ingredients} at risk: {products}. Earliest depletion in {days, plural, =0 {<1 day} one {1 day} other {# days}, affecting {batches, plural, one {# batch} other {# batches}. Potential loss: €{loss}}", "demand_forecast": "Demand for {product} is expected to increase by {increase}%", - "production_requirement": "{products} needed for {batches, plural, one {# batch} other {# batches}} of production in {days, plural, =0 {less than a day} one {# day} other {# days}}", - "safety_stock": "Safety stock replenishment: {count, plural, one {# product} other {# products}} (current: {current}, target: {target})", + "production_requirement": "{products} needed for {batches, plural, one {# batch} other {# batches} of production in {days, plural, =0 {less than a day} one {# day} other {# days}}", + "safety_stock": "Safety stock replenishment: {count, plural, one {# product} other {# products} (current: {current}, target: {target})}", "supplier_contract": "Contract with {supplier} for {products}", "seasonal_demand": "Seasonal increase of {increase}% in {products} for {season}", "forecast_demand": "Forecasted demand for {product} with {confidence}% confidence for next {period, plural, one {# day} other {# days}}" @@ -672,7 +672,7 @@ }, "pending_deliveries": { "title": "Pending Deliveries", - "count": "{count, plural, one {# delivery} other {# deliveries}} expected today", + "count": "{count, plural, one {# delivery} other {# deliveries} expected today}", "no_deliveries": "No deliveries expected today", "all_clear": "No pending deliveries today", "overdue_section": "Overdue Deliveries", @@ -686,7 +686,7 @@ }, "production_status": { "title": "Production Status", - "count": "{count, plural, one {# batch} other {# batches}} today", + "count": "{count, plural, one {# batch} other {# batches} today}", "no_production": "No production scheduled for today", "all_clear": "No production scheduled for today", "late_section": "Late to Start", @@ -738,7 +738,7 @@ "batch_delayed": "Batch Start Delayed", "generic": "Production Alert", "active": "Active", - "affected_orders": "{count, plural, one {# order} other {# orders}} affected", + "affected_orders": "{count, plural, one {# order} other {# orders} affected}", "delay_hours": "{hours}h delay", "financial_impact": "€{amount} impact", "urgent_in": "Urgent in {hours}h" diff --git a/frontend/src/locales/en/help.json b/frontend/src/locales/en/help.json index 2b710b76..d562c481 100644 --- a/frontend/src/locales/en/help.json +++ b/frontend/src/locales/en/help.json @@ -170,11 +170,6 @@ } ], "contact": { - "liveChat": { - "title": "Live Chat", - "description": "Immediate response from 9:00 to 21:00", - "action": "Start Chat" - }, "email": { "title": "Email", "description": "Response in less than 4 hours", @@ -187,7 +182,6 @@ "action": "View Docs" }, "hours": { - "liveChat": "Monday to Friday 9:00 - 21:00, Saturdays 10:00 - 18:00", "email": "24/7 (response within 4 hours during business hours)", "phone": "Monday to Friday 10:00 - 19:00 (active customers only)" } @@ -209,4 +203,4 @@ "action": "Read Tips" } } -} +} \ No newline at end of file diff --git a/frontend/src/locales/en/inventory.json b/frontend/src/locales/en/inventory.json index 152e7471..83a028b1 100644 --- a/frontend/src/locales/en/inventory.json +++ b/frontend/src/locales/en/inventory.json @@ -138,7 +138,7 @@ "validation": { "no_line_items": "At least one line item is required", "at_least_one_lot": "At least one lot is required for each line item", - "lot_quantity_mismatch": "Lot quantities ({{actual}}) must sum to actual quantity ({{expected}})", + "lot_quantity_mismatch": "Lot quantities ({actual}) must sum to actual quantity ({expected})", "expiration_required": "Expiration date is required", "quantity_required": "Quantity must be greater than 0" }, diff --git a/frontend/src/locales/en/models.json b/frontend/src/locales/en/models.json index 4e61ba3d..fa87d2bf 100644 --- a/frontend/src/locales/en/models.json +++ b/frontend/src/locales/en/models.json @@ -92,9 +92,9 @@ }, "messages": { - "training_started": "Training started for {{name}}", + "training_started": "Training started for {name}", "training_error": "Error starting training", - "retraining_started": "Retraining started for {{name}}", + "retraining_started": "Retraining started for {name}", "retraining_error": "Error retraining model" } } diff --git a/frontend/src/locales/en/onboarding.json b/frontend/src/locales/en/onboarding.json index 1e7ee2ae..31a6800a 100644 --- a/frontend/src/locales/en/onboarding.json +++ b/frontend/src/locales/en/onboarding.json @@ -223,8 +223,8 @@ "deployment": "Deployment", "processing": "Processing..." }, - "estimated_time": "Estimated time: {{minutes}} minutes", - "estimated_time_remaining": "Estimated time remaining: {{time}}", + "estimated_time": "Estimated time: {minutes} minutes", + "estimated_time_remaining": "Estimated time remaining: {time}", "description": "We're creating a personalized AI model for your bakery based on your historical data.", "training_info": { "title": "What happens during training?", diff --git a/frontend/src/locales/en/procurement.json b/frontend/src/locales/en/procurement.json index a95b87db..f2e1ac05 100644 --- a/frontend/src/locales/en/procurement.json +++ b/frontend/src/locales/en/procurement.json @@ -115,10 +115,10 @@ "auto_approve": "🤖 Auto-approve" }, "messages": { - "confirm_send": "Send order {{po_number}} to supplier?", - "confirm_receive": "Confirm receipt of order {{po_number}}?", - "confirm_items": "Mark items as received for {{po_number}}?", - "confirm_complete": "Complete order {{po_number}}?", - "cancel_reason": "Why do you want to cancel order {{po_number}}?" + "confirm_send": "Send order {po_number} to supplier?", + "confirm_receive": "Confirm receipt of order {po_number}?", + "confirm_items": "Mark items as received for {po_number}?", + "confirm_complete": "Complete order {po_number}?", + "cancel_reason": "Why do you want to cancel order {po_number}?" } } diff --git a/frontend/src/locales/en/reasoning.json b/frontend/src/locales/en/reasoning.json index e32cf21d..020261c9 100644 --- a/frontend/src/locales/en/reasoning.json +++ b/frontend/src/locales/en/reasoning.json @@ -1,10 +1,10 @@ { "orchestration": { - "daily_summary": "{purchase_orders_count, plural, =0 {} =1 {Created 1 purchase order} other {Created {purchase_orders_count} purchase orders}}{purchase_orders_count, plural, =0 {} other { and }}{production_batches_count, plural, =0 {no production batches} =1 {scheduled 1 production batch} other {scheduled {production_batches_count} production batches}}. {critical_items_count, plural, =0 {All items in stock.} =1 {1 critical item needs attention} other {{critical_items_count} critical items need attention}}{total_financial_impact_eur, select, 0 {} other { (€{total_financial_impact_eur} at risk)}}{min_depletion_hours, select, 0 {} other { - {min_depletion_hours}h until stockout}}." + "daily_summary": "{purchase_orders_count, plural, =0 {} =1 {Created 1 purchase order} other {Created {purchase_orders_count} purchase orders}{purchase_orders_count, plural, =0 {} other { and }{production_batches_count, plural, =0 {no production batches} =1 {scheduled 1 production batch} other {scheduled {production_batches_count} production batches}. {critical_items_count, plural, =0 {All items in stock.} =1 {1 critical item needs attention} other {critical_items_count} critical items need attention}{total_financial_impact_eur, select, 0 {} other { (€{total_financial_impact_eur} at risk)}{min_depletion_hours, select, 0 {} other { - {min_depletion_hours}h until stockout}.}}" }, "purchaseOrder": { "low_stock_detection": "Low stock for {supplier_name}. Current stock of {product_names_joined} will run out in {days_until_stockout} days.", - "low_stock_detection_detailed": "{critical_product_count, plural, =1 {{critical_products_0} will deplete in {min_depletion_hours} hours} other {{critical_product_count} critical items running low}}. With {supplier_name}'s {supplier_lead_time_days}-day delivery, we must order {order_urgency, select, critical {IMMEDIATELY} urgent {TODAY} important {soon} other {now}} to prevent {affected_batches_count, plural, =0 {production delays} =1 {disruption to {affected_batches_0}} other {{affected_batches_count} batch disruptions}}{potential_loss_eur, select, 0 {} other { (€{potential_loss_eur} at risk)}}.", + "low_stock_detection_detailed": "{critical_product_count, plural, =1 {critical_products_0} will deplete in {min_depletion_hours} hours} other {critical_product_count} critical items running low}. With {supplier_name}'s {supplier_lead_time_days}-day delivery, we must order {order_urgency, select, critical {IMMEDIATELY} urgent {TODAY} important {soon} other {now} to prevent {affected_batches_count, plural, =0 {production delays} =1 {disruption to {affected_batches_0} other {affected_batches_count} batch disruptions}{potential_loss_eur, select, 0 {} other { (€{potential_loss_eur} at risk)}.}}", "forecast_demand": "Order scheduled based on {forecast_period_days}-day demand forecast for {product_names_joined} from {supplier_name}.", "safety_stock_replenishment": "Replenishing safety stock for {product_names_joined} from {supplier_name}.", "supplier_contract": "Scheduled order per contract with {supplier_name}.", @@ -23,12 +23,12 @@ "regular_schedule": "Regular scheduled production of {product_name}." }, "consequence": { - "stockout_risk": "Stock-out risk in {{impact_days}} days. Products affected: {{affected_products_joined}}.", - "insufficient_supply": "Insufficient supply for {{impact_days}}-day period.", - "production_delay": "Potential production delay of {{delay_hours}} hours.", + "stockout_risk": "Stock-out risk in {impact_days} days. Products affected: {affected_products_joined}.", + "insufficient_supply": "Insufficient supply for {impact_days}-day period.", + "production_delay": "Potential production delay of {delay_hours} hours.", "customer_commitment": "Customer delivery commitment at risk.", "quality_issue": "Quality standards may be compromised.", - "cost_increase": "Material costs may increase by {{percentage}}%." + "cost_increase": "Material costs may increase by {percentage}%." }, "severity": { "critical": "Critical", @@ -50,27 +50,27 @@ "NO_DEMAND_DATA": "No historical demand data available (minimum 2 data points required)" }, "safetyStock": { - "statistical_z_score": "Safety stock calculated using statistical method (service level {{service_level}}%, z-score {{z_score}}). Based on demand std dev {{demand_std_dev}} and {{lead_time_days}}-day lead time. Result: {{safety_stock}} units.", - "advanced_variability": "Safety stock calculated with advanced variability analysis. Accounts for both demand variability (σ={{demand_std_dev}}) and lead time uncertainty (σ={{lead_time_std_dev}} days). Result: {{safety_stock}} units.", - "fixed_percentage": "Safety stock set at {{percentage}}% of {{lead_time_days}}-day demand ({{lead_time_demand}} units). Result: {{safety_stock}} units.", - "error_lead_time_invalid": "Cannot calculate safety stock: lead time ({{lead_time_days}} days) or demand std dev ({{demand_std_dev}}) is invalid.", - "error_insufficient_data": "Insufficient demand history for safety stock calculation ({{data_points}} data points, need {{min_required}})." + "statistical_z_score": "Safety stock calculated using statistical method (service level {service_level}%, z-score {z_score}). Based on demand std dev {demand_std_dev} and {lead_time_days}-day lead time. Result: {safety_stock} units.", + "advanced_variability": "Safety stock calculated with advanced variability analysis. Accounts for both demand variability (σ={demand_std_dev}) and lead time uncertainty (σ={lead_time_std_dev} days). Result: {safety_stock} units.", + "fixed_percentage": "Safety stock set at {percentage}% of {lead_time_days}-day demand ({lead_time_demand} units). Result: {safety_stock} units.", + "error_lead_time_invalid": "Cannot calculate safety stock: lead time ({lead_time_days} days) or demand std dev ({demand_std_dev}) is invalid.", + "error_insufficient_data": "Insufficient demand history for safety stock calculation ({data_points} data points, need {min_required})." }, "priceForecaster": { - "decrease_expected": "Price expected to decrease {{change_pct}}% over next {{forecast_days}} days. Current: €{{current_price}}, forecast: €{{forecast_mean}}. Recommendation: Wait for better price.", - "increase_expected": "Price expected to increase {{change_pct}}% over next {{forecast_days}} days. Current: €{{current_price}}, forecast: €{{forecast_mean}}. Recommendation: Buy now to lock in current price.", - "high_volatility": "High price volatility detected (CV={{coefficient}}). Average daily price change: {{avg_daily_change_pct}}%. Recommendation: Wait for price dip.", - "below_average": "Current price €{{current_price}} is {{below_avg_pct}}% below historical average (€{{mean_price}}). Favorable buying opportunity.", - "stable": "Price is stable. Current: €{{current_price}}, forecast: €{{forecast_mean}} ({{expected_change_pct}}% change expected). Normal procurement timing recommended.", - "insufficient_data": "Insufficient price history for reliable forecast ({{history_days}} days available, need {{min_required_days}} days)." + "decrease_expected": "Price expected to decrease {change_pct}% over next {forecast_days} days. Current: €{current_price}, forecast: €{forecast_mean}. Recommendation: Wait for better price.", + "increase_expected": "Price expected to increase {change_pct}% over next {forecast_days} days. Current: €{current_price}, forecast: €{forecast_mean}. Recommendation: Buy now to lock in current price.", + "high_volatility": "High price volatility detected (CV={coefficient}). Average daily price change: {avg_daily_change_pct}%. Recommendation: Wait for price dip.", + "below_average": "Current price €{current_price} is {below_avg_pct}% below historical average (€{mean_price}). Favorable buying opportunity.", + "stable": "Price is stable. Current: €{current_price}, forecast: €{forecast_mean} ({expected_change_pct}% change expected). Normal procurement timing recommended.", + "insufficient_data": "Insufficient price history for reliable forecast ({history_days} days available, need {min_required_days} days)." }, "optimization": { - "eoq_base": "Economic Order Quantity calculated: {{eoq}} units (required: {{required_quantity}}, annual demand: {{annual_demand}}). Optimized for {{optimal_quantity}} units.", - "moq_applied": "Minimum order quantity constraint applied: {{moq}} units.", - "max_applied": "Maximum order quantity constraint applied: {{max_qty}} units.", - "no_tiers": "No price tiers available for this product. Base quantity: {{base_quantity}} units at €{{unit_price}} per unit.", - "current_tier": "Current pricing tier: €{{current_tier_price}} per unit for {{base_quantity}} units (total: €{{base_cost}}).", - "tier_upgraded": "Upgraded to better price tier! Ordering {{tier_min_qty}} units ({{additional_qty}} extra) at €{{tier_price}} per unit saves €{{savings}} compared to {{base_quantity}} units at €{{base_price}}." + "eoq_base": "Economic Order Quantity calculated: {eoq} units (required: {required_quantity}, annual demand: {annual_demand}). Optimized for {optimal_quantity} units.", + "moq_applied": "Minimum order quantity constraint applied: {moq} units.", + "max_applied": "Maximum order quantity constraint applied: {max_qty} units.", + "no_tiers": "No price tiers available for this product. Base quantity: {base_quantity} units at €{unit_price} per unit.", + "current_tier": "Current pricing tier: €{current_tier_price} per unit for {base_quantity} units (total: €{base_cost}).", + "tier_upgraded": "Upgraded to better price tier! Ordering {tier_min_qty} units ({additional_qty} extra) at €{tier_price} per unit saves €{savings} compared to {base_quantity} units at €{base_price}." }, "jtbd": { "health_status": { @@ -80,12 +80,12 @@ "green_simple": "✅ Everything is ready for today", "yellow_simple": "⚠️ Some items need attention", "red_simple": "🔴 Critical issues require action", - "yellow_simple_with_count": "⚠️ {count} action{count, plural, one {} other {s}} needed", + "yellow_simple_with_count": "⚠️ {count} action{count, plural, one {} other {s} needed}", "last_updated": "Last updated", "next_check": "Next check", "never": "Never", "critical_issues": "{count} critical issue{count, plural, one {} other {s}}", - "actions_needed": "{count} action{count, plural, one {} other {s}} needed" + "actions_needed": "{count} action{count, plural, one {} other {s} needed}" }, "action_queue": { "title": "What Needs Your Attention", @@ -131,7 +131,7 @@ "historical_demand": "Historical demand", "inventory_levels": "Inventory levels", "ai_optimization": "AI optimization", - "actions_required": "{count} item{count, plural, one {} other {s}} need{count, plural, one {s} other {}}} your approval before proceeding", + "actions_required": "{count} item{count, plural, one {} other {s} need{count, plural, one {s} other {} your approval before proceeding}}", "no_tenant_error": "No tenant ID found. Please ensure you're logged in.", "planning_started": "Planning started successfully", "planning_failed": "Failed to start planning", @@ -170,9 +170,9 @@ } }, "types": { - "low_stock_detection": "Low stock detected for {{product_name}}. Stock will run out in {{days_until_stockout}} days.", + "low_stock_detection": "Low stock detected for {product_name}. Stock will run out in {days_until_stockout} days.", "stockout_prevention": "Preventing stockout for critical ingredients", - "forecast_demand": "Based on demand forecast: {{predicted_demand}} units predicted ({{confidence_score}}% confidence)", + "forecast_demand": "Based on demand forecast: {predicted_demand} units predicted ({confidence_score}% confidence)", "customer_orders": "Fulfilling confirmed customer orders", "seasonal_demand": "Anticipated seasonal demand increase", "inventory_replenishment": "Regular inventory replenishment", diff --git a/frontend/src/locales/en/setup_wizard.json b/frontend/src/locales/en/setup_wizard.json index ccaca349..faca8ebc 100644 --- a/frontend/src/locales/en/setup_wizard.json +++ b/frontend/src/locales/en/setup_wizard.json @@ -36,7 +36,7 @@ "add_another": "Add Another Supplier", "manage_products": "Manage Products", "products": "products", - "products_for": "Products for {{name}}", + "products_for": "Products for {name}", "add_products": "Add Products", "no_products_available": "No products available", "select_products": "Select Products", @@ -115,6 +115,7 @@ "expiration_past": "Expiration date is in the past", "expiring_soon": "Warning: This ingredient expires very soon!" }, + "batch_label": "Batch", "templates": { "basic-bakery": "Basic Bakery Ingredients", "basic-bakery-desc": "Essential ingredients for any bakery", @@ -130,6 +131,9 @@ "why": "Recipes connect your inventory to production. The system will calculate exact costs per item, track ingredient consumption, and help you optimize your menu profitability.", "quick_start": "Recipe Templates", "quick_start_desc": "Start with proven recipes and customize to your needs", + "template_ingredients": "Ingredients:", + "template_instructions": "Instructions:", + "template_tips": "Tips:", "category": { "breads": "Breads", "pastries": "Pastries", @@ -219,17 +223,29 @@ "fields": { "name": "Full Name", "email": "Email Address", + "password": "Password", + "confirm_password": "Confirm Password", + "phone": "Phone", "role": "Role" }, "placeholders": { "name": "e.g., María García", - "email": "e.g., maria@panaderia.com" + "email": "e.g., maria@panaderia.com", + "password": "••••••••", + "confirm_password": "••••••••", + "phone": "+34 600 000 000" }, + "email_hint": "This will be used as their username to log in", + "password_hint": "Minimum 8 characters", "errors": { "name_required": "Name is required", "email_required": "Email is required", "email_invalid": "Invalid email format", - "email_duplicate": "This email is already added" + "email_duplicate": "This email is already added", + "password_required": "Password is required", + "password_min_length": "Password must be at least 8 characters", + "confirm_password_required": "Please confirm the password", + "passwords_mismatch": "Passwords do not match" } }, "review": { @@ -250,7 +266,7 @@ "quality_title": "Quality Check Templates", "required": "Required", "ready_title": "Your Bakery is Ready to Go!", - "ready_message": "You've successfully configured {{suppliers}} suppliers, {{ingredients}} ingredients, and {{recipes}} recipes. Click 'Complete Setup' to finish and start using the system.", + "ready_message": "You've successfully configured {suppliers} suppliers, {ingredients} ingredients, and {recipes} recipes. Click 'Complete Setup' to finish and start using the system.", "help": "Need to make changes? Use the \"Back\" button to return to any step." }, "completion": { diff --git a/frontend/src/locales/en/suppliers.json b/frontend/src/locales/en/suppliers.json index aa90296d..36a741a4 100644 --- a/frontend/src/locales/en/suppliers.json +++ b/frontend/src/locales/en/suppliers.json @@ -213,7 +213,7 @@ }, "delete": { "title": "Remove Product from Supplier", - "description": "Are you sure you want to remove {{product}} from this supplier's price list?" + "description": "Are you sure you want to remove {product} from this supplier's price list?" } }, "delete": { diff --git a/frontend/src/locales/es/auth.json b/frontend/src/locales/es/auth.json index 94d68143..14e650e5 100644 --- a/frontend/src/locales/es/auth.json +++ b/frontend/src/locales/es/auth.json @@ -169,7 +169,7 @@ "email_required": "El correo electrónico es requerido", "email_invalid": "Ingresa un correo electrónico válido", "password_required": "La contraseña es requerida", - "password_min_length": "La contraseña debe tener al menos {{min}} caracteres", + "password_min_length": "La contraseña debe tener al menos {min} caracteres", "password_weak": "La contraseña es muy débil", "passwords_must_match": "Las contraseñas deben coincidir", "first_name_required": "El nombre es requerido", diff --git a/frontend/src/locales/es/blog.json b/frontend/src/locales/es/blog.json index ba621b3d..00195997 100644 --- a/frontend/src/locales/es/blog.json +++ b/frontend/src/locales/es/blog.json @@ -11,7 +11,7 @@ }, "post": { "read_more": "Leer artículo completo", - "read_time": "{{time}} min" + "read_time": "{time} min" }, "categories": { "management": "Gestión", diff --git a/frontend/src/locales/es/common.json b/frontend/src/locales/es/common.json index 60407b02..044e459b 100644 --- a/frontend/src/locales/es/common.json +++ b/frontend/src/locales/es/common.json @@ -375,12 +375,6 @@ "terms": "Términos", "cookies": "Cookies" }, - "social_follow": "Síguenos en redes sociales", - "social_labels": { - "twitter": "Twitter", - "linkedin": "LinkedIn", - "github": "GitHub" - }, "made_with_love": "Hecho con amor en Madrid" }, "breadcrumbs": { diff --git a/frontend/src/locales/es/contact.json b/frontend/src/locales/es/contact.json new file mode 100644 index 00000000..703f2ab9 --- /dev/null +++ b/frontend/src/locales/es/contact.json @@ -0,0 +1,83 @@ +{ + "hero": { + "badge": "Contacto y Soporte", + "title": "Estamos Aquí Para", + "title_accent": "Ayudarte", + "subtitle": "¿Tienes preguntas? ¿Necesitas ayuda? Nuestro equipo está listo para asistirte" + }, + "methods": { + "title": "Múltiples Formas de Contactar", + "subtitle": "Elige el método que más te convenga", + "email": { + "title": "Email", + "description": "soporte@panaderia-ia.com", + "detail": "Respuesta en menos de 4 horas" + }, + "phone": { + "title": "Teléfono", + "description": "+34 XXX XXX XXX", + "detail": "Lunes a Viernes: 10:00 - 19:00 CET" + }, + "office": { + "title": "Oficina", + "description": "Madrid, España", + "detail": "Con cita previa" + } + }, + "form": { + "title": "Envíanos un Mensaje", + "subtitle": "Completa el formulario y te responderemos lo antes posible", + "success": { + "title": "¡Mensaje enviado!", + "message": "Te responderemos pronto." + }, + "error": { + "title": "Error al enviar.", + "message": "Por favor, inténtalo de nuevo." + }, + "fields": { + "name": "Nombre Completo", + "name_placeholder": "Tu nombre", + "email": "Email", + "email_placeholder": "tu@email.com", + "phone": "Teléfono (opcional)", + "phone_placeholder": "+34 XXX XXX XXX", + "bakery_name": "Nombre de tu Panadería (opcional)", + "bakery_name_placeholder": "Panadería Ejemplo", + "type": "Tipo de Consulta", + "type_options": { + "general": "Consulta General", + "technical": "Soporte Técnico", + "sales": "Información Comercial", + "feedback": "Feedback/Sugerencias" + }, + "subject": "Asunto", + "subject_placeholder": "¿En qué podemos ayudarte?", + "message": "Mensaje", + "message_placeholder": "Cuéntanos más sobre tu consulta o problema..." + }, + "submit": "Enviar Mensaje", + "sending": "Enviando...", + "privacy": "Al enviar este formulario, aceptas nuestra Política de Privacidad", + "required_indicator": "*" + }, + "footer": { + "hours": { + "title": "Horarios de Atención", + "email": { + "label": "Email:", + "detail": "24/7 (respuesta en menos de 4 horas en horario laboral)" + }, + "phone": { + "label": "Teléfono:", + "detail": "Lunes a Viernes: 10:00 - 19:00 CET (solo clientes activos)" + } + }, + "faq": { + "title": "¿Buscas Respuestas Rápidas?", + "description": "Muchas preguntas ya tienen respuesta en nuestro Centro de Ayuda y Documentación", + "help_center": "Ver Centro de Ayuda →", + "docs": "Leer Documentación →" + } + } +} \ No newline at end of file diff --git a/frontend/src/locales/es/dashboard.json b/frontend/src/locales/es/dashboard.json index ed6d8c53..5a28e179 100644 --- a/frontend/src/locales/es/dashboard.json +++ b/frontend/src/locales/es/dashboard.json @@ -190,7 +190,7 @@ } }, "production": { - "scheduled_based_on": "Programado según {{type}}", + "scheduled_based_on": "Programado según {type}", "status": { "completed": "COMPLETADO", "in_progress": "EN PROGRESO", @@ -225,26 +225,26 @@ }, "health": { "production_on_schedule": "Producción a tiempo", - "production_delayed": "{count} lote{count, plural, one {} other {s}} de producción retrasado{count, plural, one {} other {s}}", - "production_late_to_start": "{count} lote{count, plural, one {} other {s}} no iniciado{count, plural, one {} other {s}} a tiempo", - "production_delayed_and_late": "{delayed} lote{delayed, plural, one {} other {s}} retrasado{delayed, plural, one {} other {s}} y {late} no iniciado{late, plural, one {} other {s}}", - "production_issues": "{total} problema{total, plural, one {} other {s}} de producción", - "production_ai_prevented": "IA evitó {count} retraso{count, plural, one {} other {s}} de producción", + "production_delayed": "{count} lote{count, plural, one {} other {s} de producción retrasado{count, plural, one {} other {s}}", + "production_late_to_start": "{count} lote{count, plural, one {} other {s} no iniciado{count, plural, one {} other {s} a tiempo}}", + "production_delayed_and_late": "{delayed} lote{delayed, plural, one {} other {s} retrasado{delayed, plural, one {} other {s} y {late} no iniciado{late, plural, one {} other {s}}", + "production_issues": "{total} problema{total, plural, one {} other {s} de producción}", + "production_ai_prevented": "IA evitó {count} retraso{count, plural, one {} other {s} de producción}", "all_ingredients_in_stock": "Todos los ingredientes en stock", - "ingredients_out_of_stock": "{count} ingrediente{count, plural, one {} other {s}} sin stock", - "inventory_ai_prevented": "IA evitó {count} problema{count, plural, one {} other {s}} de inventario", + "ingredients_out_of_stock": "{count} ingrediente{count, plural, one {} other {s} sin stock}", + "inventory_ai_prevented": "IA evitó {count} problema{count, plural, one {} other {s} de inventario}", "no_pending_approvals": "Sin aprobaciones pendientes", - "approvals_awaiting": "{count} orden{count, plural, one {} other {es}} de compra esperando aprobación", - "procurement_ai_prevented": "IA creó {count} orden{count, plural, one {} other {es}} de compra automáticamente", + "approvals_awaiting": "{count} orden{count, plural, one {} other {es} de compra esperando aprobación}", + "procurement_ai_prevented": "IA creó {count} orden{count, plural, one {} other {es} de compra automáticamente}", "deliveries_on_track": "Todas las entregas a tiempo", - "deliveries_overdue": "{count} entrega{count, plural, one {} other {s}} atrasada{count, plural, one {} other {s}}", - "deliveries_ai_prevented": "IA evitó {count} problema{count, plural, one {} other {s}} de entrega", - "deliveries_pending": "{count} entrega{count, plural, one {} other {s}} pendiente{count, plural, one {} other {s}}", + "deliveries_overdue": "{count} entrega{count, plural, one {} other {s} atrasada{count, plural, one {} other {s}}", + "deliveries_ai_prevented": "IA evitó {count} problema{count, plural, one {} other {s} de entrega}", + "deliveries_pending": "{count} entrega{count, plural, one {} other {s} pendiente{count, plural, one {} other {s}}", "all_systems_operational": "Todos los sistemas operativos", - "critical_issues": "{count} problema{count, plural, one {} other {s}} crítico{count, plural, one {} other {s}}", + "critical_issues": "{count} problema{count, plural, one {} other {s} crítico{count, plural, one {} other {s}}", "headline_green": "Tu panadería funciona sin problemas", - "headline_yellow_approvals": "Por favor revisa {count} aprobación{count, plural, one {} other {es}} pendiente{count, plural, one {} other {s}}", - "headline_yellow_alerts": "Tienes {count} alerta{count, plural, one {} other {s}} que necesita{count, plural, one {} other {n}} atención", + "headline_yellow_approvals": "Por favor revisa {count} aprobación{count, plural, one {} other {es} pendiente{count, plural, one {} other {s}}", + "headline_yellow_alerts": "Tienes {count} alerta{count, plural, one {} other {s} que necesita{count, plural, one {} other {n} atención}}", "headline_yellow_general": "Algunos elementos necesitan tu atención", "headline_red": "Problemas críticos requieren acción inmediata" }, @@ -336,7 +336,7 @@ "user_needed": "Usuario Necesario", "needs_review": "necesita tu revisión", "all_handled": "todo manejado por IA", - "prevented_badge": "{count} problema{{count, plural, one {} other {s}}} evitado{{count, plural, one {} other {s}}}", + "prevented_badge": "{count} problema{count, plural, one {} other {s} evitado{count, plural, one {} other {s}}", "prevented_description": "La IA manejó estos proactivamente antes de que se convirtieran en problemas", "analyzed_title": "Lo Que Analicé", "actions_taken": "Lo Que Hice", @@ -473,7 +473,7 @@ "no_forecast_data": "No hay datos de pronóstico disponibles", "no_performance_data": "No hay datos de rendimiento disponibles", "no_distribution_data": "No hay datos de distribución disponibles", - "performance_based_on": "Rendimiento basado en {{metric}} durante {{period}} días", + "performance_based_on": "Rendimiento basado en {metric} durante {period} días", "network_performance": "Rendimiento de Red", "performance_description": "Comparar rendimiento en todas las tiendas de tu red", "performance_variance": "Variación de Rendimiento", @@ -524,7 +524,7 @@ "set_network_targets": "Establecer Objetivos de Red", "schedule_knowledge_sharing": "Programar Compartición de Conocimientos", "create_improvement_plan": "Crear Plan de Mejora", - "performance_based_on_period": "Rendimiento basado en {{metric}} durante {{period}} días", + "performance_based_on_period": "Rendimiento basado en {metric} durante {period} días", "ranking": "Clasificación", "rank": "Posición", "outlet": "Tienda", @@ -656,7 +656,7 @@ "new_dashboard": { "system_status": { "title": "Estado del Sistema", - "issues_requiring_action": "{count, plural, one {# problema requiere} other {# problemas requieren}} tu acción", + "issues_requiring_action": "{count, plural, one {# problema requiere} other {# problemas requieren} tu acción}", "all_clear": "Todos los sistemas funcionan correctamente", "never_run": "Nunca ejecutado", "action_needed_label": "acción requerida", @@ -673,7 +673,7 @@ }, "pending_purchases": { "title": "Compras Pendientes", - "count": "{count, plural, one {# orden} other {# órdenes}} esperando aprobación", + "count": "{count, plural, one {# orden} other {# órdenes} esperando aprobación}", "no_pending": "Sin órdenes de compra pendientes", "all_clear": "Sin órdenes de compra pendientes de aprobación", "po_number": "OC #{number}", @@ -684,10 +684,10 @@ "ai_reasoning": "IA creó esta OC porque:", "reasoning": { "low_stock": "{ingredient} se agotará en {days, plural, =0 {menos de un día} one {# día} other {# días}}", - "low_stock_detailed": "{count, plural, one {# ingrediente crítico} other {# ingredientes críticos}} en riesgo: {products}. Agotamiento más temprano en {days, plural, =0 {<1 día} one {1 día} other {# días}}, afectando {batches, plural, one {# lote} other {# lotes}}. Pérdida potencial: €{loss}", + "low_stock_detailed": "{count, plural, one {# ingrediente crítico} other {# ingredientes críticos} en riesgo: {products}. Agotamiento más temprano en {days, plural, =0 {<1 día} one {1 día} other {# días}, afectando {batches, plural, one {# lote} other {# lotes}. Pérdida potencial: €{loss}}", "demand_forecast": "Se espera que la demanda de {product} aumente un {increase}%", - "production_requirement": "Se necesitan {products} para {batches, plural, one {# lote} other {# lotes}} de producción en {days, plural, =0 {menos de un día} one {# día} other {# días}}", - "safety_stock": "Reabastecimiento de stock de seguridad: {count, plural, one {# producto} other {# productos}} (actual: {current}, objetivo: {target})", + "production_requirement": "Se necesitan {products} para {batches, plural, one {# lote} other {# lotes} de producción en {days, plural, =0 {menos de un día} one {# día} other {# días}}", + "safety_stock": "Reabastecimiento de stock de seguridad: {count, plural, one {# producto} other {# productos} (actual: {current}, objetivo: {target})}", "supplier_contract": "Contrato con {supplier} para {products}", "seasonal_demand": "Aumento estacional del {increase}% en {products} para {season}", "forecast_demand": "Demanda prevista de {product} con {confidence}% de confianza para los próximos {period, plural, one {# día} other {# días}}" @@ -695,7 +695,7 @@ }, "pending_deliveries": { "title": "Entregas Pendientes", - "count": "{count, plural, one {# entrega} other {# entregas}} esperadas hoy", + "count": "{count, plural, one {# entrega} other {# entregas} esperadas hoy}", "no_deliveries": "Sin entregas esperadas hoy", "all_clear": "Sin entregas pendientes hoy", "overdue_section": "Entregas Atrasadas", @@ -709,7 +709,7 @@ }, "production_status": { "title": "Estado de Producción", - "count": "{count, plural, one {# lote} other {# lotes}} hoy", + "count": "{count, plural, one {# lote} other {# lotes} hoy}", "no_production": "Sin producción programada para hoy", "all_clear": "Sin producción programada para hoy", "late_section": "Atrasados para Empezar", @@ -761,7 +761,7 @@ "batch_delayed": "Lote con Inicio Retrasado", "generic": "Alerta de Producción", "active": "Activo", - "affected_orders": "{count, plural, one {# pedido} other {# pedidos}} afectados", + "affected_orders": "{count, plural, one {# pedido} other {# pedidos} afectados}", "delay_hours": "{hours}h de retraso", "financial_impact": "€{amount} de impacto", "urgent_in": "Urgente en {hours}h" diff --git a/frontend/src/locales/es/errors.json b/frontend/src/locales/es/errors.json index c8337759..902e1622 100644 --- a/frontend/src/locales/es/errors.json +++ b/frontend/src/locales/es/errors.json @@ -40,10 +40,10 @@ "invalid_date": "Fecha inválida", "invalid_number": "Número inválido", "invalid_url": "URL inválida", - "min_length": "Mínimo {{min}} caracteres", - "max_length": "Máximo {{max}} caracteres", - "min_value": "Valor mínimo: {{min}}", - "max_value": "Valor máximo: {{max}}", + "min_length": "Mínimo {min} caracteres", + "max_length": "Máximo {max} caracteres", + "min_value": "Valor mínimo: {min}", + "max_value": "Valor máximo: {max}", "invalid_format": "Formato inválido", "invalid_selection": "Selección inválida", "file_too_large": "Archivo demasiado grande", diff --git a/frontend/src/locales/es/help.json b/frontend/src/locales/es/help.json index a9bf22cf..8a8ebd11 100644 --- a/frontend/src/locales/es/help.json +++ b/frontend/src/locales/es/help.json @@ -797,15 +797,10 @@ { "category": "support", "question": "¿Qué tipo de soporte ofrecen?", - "answer": "Soporte 24/7 en español por: Email (respuesta en <4h), Chat en vivo (9:00-21:00), Videollamada (con cita previa). Durante el piloto, también tienes acceso directo a los fundadores por WhatsApp." + "answer": "Soporte 24/7 en español por: Email (respuesta en <4h), Videollamada (con cita previa). Durante el piloto, también tienes acceso directo a los fundadores por WhatsApp." } ], "contact": { - "liveChat": { - "title": "Chat en Vivo", - "description": "Respuesta inmediata de 9:00 a 21:00", - "action": "Iniciar Chat" - }, "email": { "title": "Email", "description": "Respuesta en menos de 4 horas", @@ -818,9 +813,8 @@ "action": "Ver Docs" }, "hours": { - "liveChat": "Lunes a Viernes 9:00 - 21:00, Sábados 10:00 - 18:00", - "email": "24/7 (respuesta en menos de 4 horas en horario laboral)", - "phone": "Lunes a Viernes 10:00 - 19:00 (solo para clientes activos)" + "email": "24/7 (respuesta en 4 horas en horario laboral)", + "phone": "Lunes a Viernes 10:00 - 19:00 (solo clientes activos)" } }, "resources": { @@ -840,4 +834,4 @@ "action": "Leer Tips" } } -} +} \ No newline at end of file diff --git a/frontend/src/locales/es/models.json b/frontend/src/locales/es/models.json index 342fbdb9..bdaeaf06 100644 --- a/frontend/src/locales/es/models.json +++ b/frontend/src/locales/es/models.json @@ -93,9 +93,9 @@ }, "messages": { - "training_started": "Entrenamiento iniciado para {{name}}", + "training_started": "Entrenamiento iniciado para {name}", "training_error": "Error al iniciar el entrenamiento", - "retraining_started": "Reentrenamiento iniciado para {{name}}", + "retraining_started": "Reentrenamiento iniciado para {name}", "retraining_error": "Error al reentrenar el modelo" } } diff --git a/frontend/src/locales/es/onboarding.json b/frontend/src/locales/es/onboarding.json index 477431b1..600581b7 100644 --- a/frontend/src/locales/es/onboarding.json +++ b/frontend/src/locales/es/onboarding.json @@ -244,8 +244,8 @@ "deployment": "Despliegue", "processing": "Procesando..." }, - "estimated_time": "Tiempo estimado: {{minutes}} minutos", - "estimated_time_remaining": "Tiempo restante estimado: {{time}}", + "estimated_time": "Tiempo estimado: {minutes} minutos", + "estimated_time_remaining": "Tiempo restante estimado: {time}", "description": "Estamos creando un modelo de IA personalizado para tu panadería basado en tus datos históricos.", "training_info": { "title": "¿Qué sucede durante el entrenamiento?", diff --git a/frontend/src/locales/es/procurement.json b/frontend/src/locales/es/procurement.json index b77043ad..1399b90f 100644 --- a/frontend/src/locales/es/procurement.json +++ b/frontend/src/locales/es/procurement.json @@ -115,10 +115,10 @@ "auto_approve": "🤖 Auto-aprobable" }, "messages": { - "confirm_send": "¿Enviar la orden {{po_number}} al proveedor?", - "confirm_receive": "¿Confirmar recepción de la orden {{po_number}}?", - "confirm_items": "¿Marcar items como recibidos para {{po_number}}?", - "confirm_complete": "¿Completar la orden {{po_number}}?", - "cancel_reason": "¿Por qué deseas cancelar la orden {{po_number}}?" + "confirm_send": "¿Enviar la orden {po_number} al proveedor?", + "confirm_receive": "¿Confirmar recepción de la orden {po_number}?", + "confirm_items": "¿Marcar items como recibidos para {po_number}?", + "confirm_complete": "¿Completar la orden {po_number}?", + "cancel_reason": "¿Por qué deseas cancelar la orden {po_number}?" } } diff --git a/frontend/src/locales/es/reasoning.json b/frontend/src/locales/es/reasoning.json index 3fc56b4a..a2094022 100644 --- a/frontend/src/locales/es/reasoning.json +++ b/frontend/src/locales/es/reasoning.json @@ -1,10 +1,10 @@ { "orchestration": { - "daily_summary": "{purchase_orders_count, plural, =0 {} =1 {Creé 1 orden de compra} other {Creé {purchase_orders_count} órdenes de compra}}{purchase_orders_count, plural, =0 {} other { y }}{production_batches_count, plural, =0 {ningún lote de producción} =1 {programé 1 lote de producción} other {programé {production_batches_count} lotes de producción}}. {critical_items_count, plural, =0 {Todo en stock.} =1 {1 artículo crítico necesita atención} other {{critical_items_count} artículos críticos necesitan atención}}{total_financial_impact_eur, select, 0 {} other { (€{total_financial_impact_eur} en riesgo)}}{min_depletion_hours, select, 0 {} other { - {min_depletion_hours}h hasta agotamiento}}." + "daily_summary": "{purchase_orders_count, plural, =0 {} =1 {Creé 1 orden de compra} other {Creé {purchase_orders_count} órdenes de compra}{purchase_orders_count, plural, =0 {} other { y }{production_batches_count, plural, =0 {ningún lote de producción} =1 {programé 1 lote de producción} other {programé {production_batches_count} lotes de producción}. {critical_items_count, plural, =0 {Todo en stock.} =1 {1 artículo crítico necesita atención} other {critical_items_count} artículos críticos necesitan atención}{total_financial_impact_eur, select, 0 {} other { (€{total_financial_impact_eur} en riesgo)}{min_depletion_hours, select, 0 {} other { - {min_depletion_hours}h hasta agotamiento}.}}" }, "purchaseOrder": { "low_stock_detection": "Stock bajo para {supplier_name}. El stock actual de {product_names_joined} se agotará en {days_until_stockout} días.", - "low_stock_detection_detailed": "{critical_product_count, plural, =1 {{critical_products_0} se agotará en {min_depletion_hours} horas} other {{critical_product_count} productos críticos escasos}}. Con entrega de {supplier_lead_time_days} días de {supplier_name}, debemos pedir {order_urgency, select, critical {INMEDIATAMENTE} urgent {HOY} important {pronto} other {ahora}} para evitar {affected_batches_count, plural, =0 {retrasos en producción} =1 {interrupción del lote {affected_batches_0}} other {interrupción de {affected_batches_count} lotes}}{potential_loss_eur, select, 0 {} other { (€{potential_loss_eur} en riesgo)}}.", + "low_stock_detection_detailed": "{critical_product_count, plural, =1 {critical_products_0} se agotará en {min_depletion_hours} horas} other {critical_product_count} productos críticos escasos}. Con entrega de {supplier_lead_time_days} días de {supplier_name}, debemos pedir {order_urgency, select, critical {INMEDIATAMENTE} urgent {HOY} important {pronto} other {ahora} para evitar {affected_batches_count, plural, =0 {retrasos en producción} =1 {interrupción del lote {affected_batches_0} other {interrupción de {affected_batches_count} lotes}{potential_loss_eur, select, 0 {} other { (€{potential_loss_eur} en riesgo)}.}}", "forecast_demand": "Pedido programado basado en pronóstico de demanda de {forecast_period_days} días para {product_names_joined} de {supplier_name}.", "safety_stock_replenishment": "Reposición de stock de seguridad para {product_names_joined} de {supplier_name}.", "supplier_contract": "Pedido programado según contrato con {supplier_name}.", @@ -23,12 +23,12 @@ "regular_schedule": "Producción programada regular de {product_name}." }, "consequence": { - "stockout_risk": "Riesgo de desabastecimiento en {{impact_days}} días. Productos afectados: {{affected_products_joined}}.", - "insufficient_supply": "Suministro insuficiente para período de {{impact_days}} días.", - "production_delay": "Posible retraso en producción de {{delay_hours}} horas.", + "stockout_risk": "Riesgo de desabastecimiento en {impact_days} días. Productos afectados: {affected_products_joined}.", + "insufficient_supply": "Suministro insuficiente para período de {impact_days} días.", + "production_delay": "Posible retraso en producción de {delay_hours} horas.", "customer_commitment": "Compromiso de entrega al cliente en riesgo.", "quality_issue": "Los estándares de calidad pueden verse comprometidos.", - "cost_increase": "Los costos de materiales pueden aumentar un {{percentage}}%." + "cost_increase": "Los costos de materiales pueden aumentar un {percentage}%." }, "severity": { "critical": "Crítico", @@ -50,27 +50,27 @@ "NO_DEMAND_DATA": "No hay datos históricos de demanda disponibles (se requieren mínimo 2 puntos de datos)" }, "safetyStock": { - "statistical_z_score": "Stock de seguridad calculado con método estadístico (nivel de servicio {{service_level}}%, z-score {{z_score}}). Basado en desviación estándar de demanda {{demand_std_dev}} y tiempo de entrega de {{lead_time_days}} días. Resultado: {{safety_stock}} unidades.", - "advanced_variability": "Stock de seguridad calculado con análisis avanzado de variabilidad. Considera tanto la variabilidad de demanda (σ={{demand_std_dev}}) como la incertidumbre del tiempo de entrega (σ={{lead_time_std_dev}} días). Resultado: {{safety_stock}} unidades.", - "fixed_percentage": "Stock de seguridad establecido en {{percentage}}% de la demanda de {{lead_time_days}} días ({{lead_time_demand}} unidades). Resultado: {{safety_stock}} unidades.", - "error_lead_time_invalid": "No se puede calcular el stock de seguridad: el tiempo de entrega ({{lead_time_days}} días) o la desviación estándar de demanda ({{demand_std_dev}}) no son válidos.", - "error_insufficient_data": "Historial de demanda insuficiente para calcular stock de seguridad ({{data_points}} puntos de datos, se necesitan {{min_required}})." + "statistical_z_score": "Stock de seguridad calculado con método estadístico (nivel de servicio {service_level}%, z-score {z_score}). Basado en desviación estándar de demanda {demand_std_dev} y tiempo de entrega de {lead_time_days} días. Resultado: {safety_stock} unidades.", + "advanced_variability": "Stock de seguridad calculado con análisis avanzado de variabilidad. Considera tanto la variabilidad de demanda (σ={demand_std_dev}) como la incertidumbre del tiempo de entrega (σ={lead_time_std_dev} días). Resultado: {safety_stock} unidades.", + "fixed_percentage": "Stock de seguridad establecido en {percentage}% de la demanda de {lead_time_days} días ({lead_time_demand} unidades). Resultado: {safety_stock} unidades.", + "error_lead_time_invalid": "No se puede calcular el stock de seguridad: el tiempo de entrega ({lead_time_days} días) o la desviación estándar de demanda ({demand_std_dev}) no son válidos.", + "error_insufficient_data": "Historial de demanda insuficiente para calcular stock de seguridad ({data_points} puntos de datos, se necesitan {min_required})." }, "priceForecaster": { - "decrease_expected": "Se espera que el precio disminuya {{change_pct}}% en los próximos {{forecast_days}} días. Actual: €{{current_price}}, pronóstico: €{{forecast_mean}}. Recomendación: Esperar mejor precio.", - "increase_expected": "Se espera que el precio aumente {{change_pct}}% en los próximos {{forecast_days}} días. Actual: €{{current_price}}, pronóstico: €{{forecast_mean}}. Recomendación: Comprar ahora para asegurar el precio actual.", - "high_volatility": "Alta volatilidad de precio detectada (CV={{coefficient}}). Cambio diario promedio de precio: {{avg_daily_change_pct}}%. Recomendación: Esperar caída de precio.", - "below_average": "El precio actual €{{current_price}} está {{below_avg_pct}}% por debajo del promedio histórico (€{{mean_price}}). Oportunidad favorable de compra.", - "stable": "El precio es estable. Actual: €{{current_price}}, pronóstico: €{{forecast_mean}} (se espera cambio de {{expected_change_pct}}%). Se recomienda tiempo de compra normal.", - "insufficient_data": "Historial de precios insuficiente para pronóstico confiable ({{history_days}} días disponibles, se necesitan {{min_required_days}} días)." + "decrease_expected": "Se espera que el precio disminuya {change_pct}% en los próximos {forecast_days} días. Actual: €{current_price}, pronóstico: €{forecast_mean}. Recomendación: Esperar mejor precio.", + "increase_expected": "Se espera que el precio aumente {change_pct}% en los próximos {forecast_days} días. Actual: €{current_price}, pronóstico: €{forecast_mean}. Recomendación: Comprar ahora para asegurar el precio actual.", + "high_volatility": "Alta volatilidad de precio detectada (CV={coefficient}). Cambio diario promedio de precio: {avg_daily_change_pct}%. Recomendación: Esperar caída de precio.", + "below_average": "El precio actual €{current_price} está {below_avg_pct}% por debajo del promedio histórico (€{mean_price}). Oportunidad favorable de compra.", + "stable": "El precio es estable. Actual: €{current_price}, pronóstico: €{forecast_mean} (se espera cambio de {expected_change_pct}%). Se recomienda tiempo de compra normal.", + "insufficient_data": "Historial de precios insuficiente para pronóstico confiable ({history_days} días disponibles, se necesitan {min_required_days} días)." }, "optimization": { - "eoq_base": "Cantidad Económica de Pedido calculada: {{eoq}} unidades (requerido: {{required_quantity}}, demanda anual: {{annual_demand}}). Optimizado para {{optimal_quantity}} unidades.", - "moq_applied": "Restricción de cantidad mínima de pedido aplicada: {{moq}} unidades.", - "max_applied": "Restricción de cantidad máxima de pedido aplicada: {{max_qty}} unidades.", - "no_tiers": "No hay niveles de precio disponibles para este producto. Cantidad base: {{base_quantity}} unidades a €{{unit_price}} por unidad.", - "current_tier": "Nivel de precio actual: €{{current_tier_price}} por unidad para {{base_quantity}} unidades (total: €{{base_cost}}).", - "tier_upgraded": "¡Actualizado a mejor nivel de precio! Pedir {{tier_min_qty}} unidades ({{additional_qty}} extra) a €{{tier_price}} por unidad ahorra €{{savings}} comparado con {{base_quantity}} unidades a €{{base_price}}." + "eoq_base": "Cantidad Económica de Pedido calculada: {eoq} unidades (requerido: {required_quantity}, demanda anual: {annual_demand}). Optimizado para {optimal_quantity} unidades.", + "moq_applied": "Restricción de cantidad mínima de pedido aplicada: {moq} unidades.", + "max_applied": "Restricción de cantidad máxima de pedido aplicada: {max_qty} unidades.", + "no_tiers": "No hay niveles de precio disponibles para este producto. Cantidad base: {base_quantity} unidades a €{unit_price} por unidad.", + "current_tier": "Nivel de precio actual: €{current_tier_price} por unidad para {base_quantity} unidades (total: €{base_cost}).", + "tier_upgraded": "¡Actualizado a mejor nivel de precio! Pedir {tier_min_qty} unidades ({additional_qty} extra) a €{tier_price} por unidad ahorra €{savings} comparado con {base_quantity} unidades a €{base_price}." }, "jtbd": { "health_status": { @@ -80,12 +80,12 @@ "green_simple": "✅ Todo listo para hoy", "yellow_simple": "⚠️ Algunas cosas necesitan atención", "red_simple": "🔴 Problemas críticos requieren acción", - "yellow_simple_with_count": "⚠️ {count} acción{count, plural, one {} other {es}} necesaria{count, plural, one {} other {s}}", + "yellow_simple_with_count": "⚠️ {count} acción{count, plural, one {} other {es} necesaria{count, plural, one {} other {s}}", "last_updated": "Última actualización", "next_check": "Próxima verificación", "never": "Nunca", - "critical_issues": "{count} problema{count, plural, one {} other {s}} crítico{count, plural, one {} other {s}}", - "actions_needed": "{count} acción{count, plural, one {} other {es}} necesaria{count, plural, one {} other {s}}" + "critical_issues": "{count} problema{count, plural, one {} other {s} crítico{count, plural, one {} other {s}}", + "actions_needed": "{count} acción{count, plural, one {} other {es} necesaria{count, plural, one {} other {s}}" }, "action_queue": { "title": "Qué Necesita Tu Atención", @@ -96,7 +96,7 @@ "estimated_time": "Tiempo estimado", "all_caught_up": "¡Todo al día!", "no_actions": "No hay acciones que requieran tu atención en este momento.", - "show_more": "Mostrar {count} Acción{count, plural, one {} other {es}} Más", + "show_more": "Mostrar {count} Acción{count, plural, one {} other {es} Más}", "show_less": "Mostrar Menos", "total": "total", "critical": "críticas", @@ -121,17 +121,17 @@ "run_planning": "Ejecutar Planificación Diaria", "run_info": "Ejecución de orquestación #{runNumber}", "took": "Duró {seconds}s", - "created_pos": "{count} orden{count, plural, one {} other {es}} de compra creada{count, plural, one {} other {s}}", - "scheduled_batches": "{count} lote{count, plural, one {} other {s}} de producción programado{count, plural, one {} other {s}}", + "created_pos": "{count} orden{count, plural, one {} other {es} de compra creada{count, plural, one {} other {s}}", + "scheduled_batches": "{count} lote{count, plural, one {} other {s} de producción programado{count, plural, one {} other {s}}", "show_more": "Mostrar {count} más", "show_less": "Mostrar menos", "no_actions": "¡No se necesitan nuevas acciones - todo va según lo planeado!", "based_on": "Basado en:", - "customer_orders": "{count} pedido{count, plural, one {} other {s}} de cliente", + "customer_orders": "{count} pedido{count, plural, one {} other {s} de cliente}", "historical_demand": "Demanda histórica", "inventory_levels": "Niveles de inventario", "ai_optimization": "Optimización por IA", - "actions_required": "{count} elemento{count, plural, one {} other {s}} necesita{count, plural, one {} other {n}} tu aprobación antes de continuar", + "actions_required": "{count} elemento{count, plural, one {} other {s} necesita{count, plural, one {} other {n} tu aprobación antes de continuar}}", "no_tenant_error": "No se encontró ID de inquilino. Por favor, asegúrate de haber iniciado sesión.", "planning_started": "Planificación iniciada correctamente", "planning_failed": "Error al iniciar la planificación", @@ -170,9 +170,9 @@ } }, "types": { - "low_stock_detection": "Stock bajo detectado para {{product_name}}. El stock se agotará en {{days_until_stockout}} días.", + "low_stock_detection": "Stock bajo detectado para {product_name}. El stock se agotará en {days_until_stockout} días.", "stockout_prevention": "Previniendo desabastecimiento de ingredientes críticos", - "forecast_demand": "Basado en pronóstico de demanda: {{predicted_demand}} unidades predichas ({{confidence_score}}% confianza)", + "forecast_demand": "Basado en pronóstico de demanda: {predicted_demand} unidades predichas ({confidence_score}% confianza)", "customer_orders": "Cumpliendo pedidos confirmados de clientes", "seasonal_demand": "Aumento anticipado de demanda estacional", "inventory_replenishment": "Reposición regular de inventario", diff --git a/frontend/src/locales/es/setup_wizard.json b/frontend/src/locales/es/setup_wizard.json index f673d0e2..8f707298 100644 --- a/frontend/src/locales/es/setup_wizard.json +++ b/frontend/src/locales/es/setup_wizard.json @@ -36,7 +36,7 @@ "add_another": "Agregar Otro Proveedor", "manage_products": "Gestionar Productos", "products": "productos", - "products_for": "Productos para {{name}}", + "products_for": "Productos para {name}", "add_products": "Agregar Productos", "no_products_available": "No hay productos disponibles", "select_products": "Seleccionar Productos", @@ -114,12 +114,26 @@ "quantity_required": "La cantidad debe ser mayor que cero", "expiration_past": "La fecha de vencimiento está en el pasado", "expiring_soon": "¡Advertencia: Este ingrediente vence muy pronto!" + }, + "batch_label": "Lote", + "templates": { + "basic-bakery": "Ingredientes Básicos de Panadería", + "basic-bakery-desc": "Ingredientes esenciales para cualquier panadería", + "pastry-essentials": "Esenciales de Pastelería", + "pastry-essentials-desc": "Ingredientes para pasteles y postres", + "bread-basics": "Básicos de Pan", + "bread-basics-desc": "Todo lo necesario para pan artesanal", + "chocolate-specialties": "Especialidades de Chocolate", + "chocolate-specialties-desc": "Para productos de chocolate" } }, "recipes": { "why": "Las recetas conectan tu inventario con la producción. El sistema calculará los costos exactos por artículo, rastreará el consumo de ingredientes y te ayudará a optimizar la rentabilidad de tu menú.", "quick_start": "Plantillas de Recetas", "quick_start_desc": "Comienza con recetas probadas y personalízalas según tus necesidades", + "template_ingredients": "Ingredientes:", + "template_instructions": "Instrucciones:", + "template_tips": "Consejos:", "category": { "breads": "Panes", "pastries": "Bollería", @@ -209,17 +223,29 @@ "fields": { "name": "Nombre Completo", "email": "Dirección de Correo", + "password": "Contraseña", + "confirm_password": "Confirmar Contraseña", + "phone": "Teléfono", "role": "Rol" }, "placeholders": { "name": "ej., María García", - "email": "ej., maria@panaderia.com" + "email": "ej., maria@panaderia.com", + "password": "••••••••", + "confirm_password": "••••••••", + "phone": "+34 600 000 000" }, + "email_hint": "Este será su nombre de usuario para iniciar sesión", + "password_hint": "Mínimo 8 caracteres", "errors": { "name_required": "El nombre es obligatorio", "email_required": "El correo es obligatorio", "email_invalid": "Formato de correo inválido", - "email_duplicate": "Este correo ya ha sido agregado" + "email_duplicate": "Este correo ya ha sido agregado", + "password_required": "La contraseña es obligatoria", + "password_min_length": "La contraseña debe tener al menos 8 caracteres", + "confirm_password_required": "Por favor confirme la contraseña", + "passwords_mismatch": "Las contraseñas no coinciden" } }, "review": { @@ -240,7 +266,7 @@ "quality_title": "Plantillas de Control de Calidad", "required": "Obligatorio", "ready_title": "¡Tu Panadería está Lista!", - "ready_message": "Has configurado exitosamente {{suppliers}} proveedores, {{ingredients}} ingredientes y {{recipes}} recetas. Haz clic en 'Completar Configuración' para finalizar y comenzar a usar el sistema.", + "ready_message": "Has configurado exitosamente {suppliers} proveedores, {ingredients} ingredientes y {recipes} recetas. Haz clic en 'Completar Configuración' para finalizar y comenzar a usar el sistema.", "help": "¿Necesitas hacer cambios? Usa el botón \"Atrás\" para volver a cualquier paso." }, "completion": { diff --git a/frontend/src/locales/es/suppliers.json b/frontend/src/locales/es/suppliers.json index 81569c08..16f13d9a 100644 --- a/frontend/src/locales/es/suppliers.json +++ b/frontend/src/locales/es/suppliers.json @@ -213,7 +213,7 @@ }, "delete": { "title": "Eliminar Producto del Proveedor", - "description": "¿Estás seguro de que quieres eliminar {{product}} de la lista de precios de este proveedor?" + "description": "¿Estás seguro de que quieres eliminar {product} de la lista de precios de este proveedor?" } }, "delete": { diff --git a/frontend/src/locales/eu/blog.json b/frontend/src/locales/eu/blog.json index 5ed13231..b9ed9b62 100644 --- a/frontend/src/locales/eu/blog.json +++ b/frontend/src/locales/eu/blog.json @@ -11,7 +11,7 @@ }, "post": { "read_more": "Irakurri artikulu osoa", - "read_time": "{{time}} min" + "read_time": "{time} min" }, "categories": { "management": "Kudeaketa", diff --git a/frontend/src/locales/eu/common.json b/frontend/src/locales/eu/common.json index 99416337..b08126bf 100644 --- a/frontend/src/locales/eu/common.json +++ b/frontend/src/locales/eu/common.json @@ -349,12 +349,6 @@ "terms": "Baldintzak", "cookies": "Cookie-ak" }, - "social_follow": "Jarraitu gaitzazu sare sozialetan", - "social_labels": { - "twitter": "Twitter", - "linkedin": "LinkedIn", - "github": "GitHub" - }, "made_with_love": "Madrilen maitasunez eginda" }, "breadcrumbs": { @@ -464,4 +458,4 @@ "file_too_large": "Fitxategia handiegia da", "invalid_file_type": "Fitxategi mota baliogabea" } -} +} \ No newline at end of file diff --git a/frontend/src/locales/eu/contact.json b/frontend/src/locales/eu/contact.json new file mode 100644 index 00000000..ddf16bc0 --- /dev/null +++ b/frontend/src/locales/eu/contact.json @@ -0,0 +1,83 @@ +{ + "hero": { + "badge": "Kontaktua eta Laguntza", + "title": "Hemen Gaude Zu", + "title_accent": "Laguntzeko", + "subtitle": "Galderarik duzu? Laguntza behar duzu? Gure taldea prest dago zu laguntzeko" + }, + "methods": { + "title": "Kontaktuan Jartzeko Hainbat Modu", + "subtitle": "Aukeratu zuretzat egokiena den bidea", + "email": { + "title": "Emaila", + "description": "laguntza@panaderia-ia.com", + "detail": "4 ordu baino gutxiagotan erantzuna" + }, + "phone": { + "title": "Telefonoa", + "description": "+34 XXX XXX XXX", + "detail": "Astelehenetik Ostiralera: 10:00 - 19:00 CET" + }, + "office": { + "title": "Bulegoa", + "description": "Madril, Espainia", + "detail": "Hitzorduarekin soilik" + } + }, + "form": { + "title": "Bidali Mezu Bat", + "subtitle": "Bete formularioa eta lehenbailehen erantzungo dizugu", + "success": { + "title": "Mezua bidali da!", + "message": "Laster erantzungo dizugu." + }, + "error": { + "title": "Errorea bidaltzean.", + "message": "Mesedez, saiatu berriro." + }, + "fields": { + "name": "Izen-abizenak", + "name_placeholder": "Zure izena", + "email": "Emaila", + "email_placeholder": "zure@emaila.com", + "phone": "Telefonoa (aukerakoa)", + "phone_placeholder": "+34 XXX XXX XXX", + "bakery_name": "Zure Okindegiaren Izena (aukerakoa)", + "bakery_name_placeholder": "Adibidezko Okindegia", + "type": "Kontsulta Mota", + "type_options": { + "general": "Kontsulta Orokorra", + "technical": "Laguntza Teknikoa", + "sales": "Informazio Komertziala", + "feedback": "Iritziak/Iradokizunak" + }, + "subject": "Gaia", + "subject_placeholder": "Nola lagundu diezazukegu?", + "message": "Mezua", + "message_placeholder": "Kontatu iezaguzu gehiago zure kontsulta edo arazoari buruz..." + }, + "submit": "Mezua Bidali", + "sending": "Bidaltzen...", + "privacy": "Formulario hau bidaltzean, gure Pribatutasun Politika onartzen duzu", + "required_indicator": "*" + }, + "footer": { + "hours": { + "title": "Arreta Ordutegia", + "email": { + "label": "Emaila:", + "detail": "24/7 (4 ordu baino gutxiagotan erantzuna lanorduetan)" + }, + "phone": { + "label": "Telefonoa:", + "detail": "Astelehenetik Ostiralera: 10:00 - 19:00 CET (bezero aktiboak soilik)" + } + }, + "faq": { + "title": "Erantzun Azkarrak Behar Dituzu?", + "description": "Galdera askok badute jada erantzuna gure Laguntza Zentroan eta Dokumentazioan", + "help_center": "Ikusi Laguntza Zentroa →", + "docs": "Irakurri Dokumentazioa →" + } + } +} \ No newline at end of file diff --git a/frontend/src/locales/eu/dashboard.json b/frontend/src/locales/eu/dashboard.json index 5d72aa5e..a73faad4 100644 --- a/frontend/src/locales/eu/dashboard.json +++ b/frontend/src/locales/eu/dashboard.json @@ -129,7 +129,7 @@ "active_count": "{count} alerta aktibo" }, "production": { - "scheduled_based_on": "{{type}} arabera programatuta", + "scheduled_based_on": "{type} arabera programatuta", "status": { "completed": "OSATUTA", "in_progress": "MARTXAN", @@ -170,15 +170,15 @@ "ingredients_out_of_stock": "{count} osagai stockik gabe", "inventory_ai_prevented": "AIk {count} inbentario arazo saihestu {count, plural, one {du} other {ditu}}", "no_pending_approvals": "Ez dago onarpen pendienteik", - "approvals_awaiting": "{count} erosketa agindu{count, plural, one {} other {k}}} onarpenaren zai", - "procurement_ai_created": "AIk {count} erosketa agindu sortu {count, plural, one {du} other {ditu}} automatikoki", + "approvals_awaiting": "{count} erosketa agindu{count, plural, one {} other {k} onarpenaren zai}", + "procurement_ai_created": "AIk {count} erosketa agindu sortu {count, plural, one {du} other {ditu} automatikoki}", "deliveries_on_track": "Entrega guztiak orduan", "deliveries_pending": "{count} entrega zain", "all_systems_operational": "Sistema guztiak martxan", "critical_issues": "{count} arazo kritiko", "headline_green": "Zure okindegia arazorik gabe dabil", "headline_yellow_approvals": "Mesedez berrikusi {count} onarpen zain", - "headline_yellow_alerts": "{count} alerta{count, plural, one {} other {k}}} arreta behar d{count, plural, one {u} other {ute}}}", + "headline_yellow_alerts": "{count} alerta{count, plural, one {} other {k} arreta behar d{count, plural, one {u} other {ute}}", "headline_yellow_general": "Zenbait elementuk zure arreta behar dute", "headline_red": "Arazo kritikoek berehalako ekintza behar dute" }, @@ -248,7 +248,7 @@ "user_needed": "Erabiltzailea Behar", "needs_review": "zure berrikuspena behar du", "all_handled": "guztia AIak kudeatua", - "prevented_badge": "{count} arazu saihestau{{count, plural, one {} other {}}", + "prevented_badge": "{count} arazu saihestau{count, plural, one {} other {}}", "prevented_description": "AIak hauek proaktiboki kudeatu zituen arazo bihurtu aurretik", "analyzed_title": "Zer Aztertu Nuen", "actions_taken": "Zer Egin Nuen", @@ -354,7 +354,7 @@ "no_forecast_data": "Ez dago iragarpen daturik erabilgarri", "no_performance_data": "Ez dago errendimendu daturik erabilgarri", "no_distribution_data": "Ez dago banaketa daturik erabilgarri", - "performance_based_on": "Errendimendua {{metric}}-n oinarrituta {{period}} egunetan", + "performance_based_on": "Errendimendua {metric}-n oinarrituta {period} egunetan", "ranking": "Sailkapena", "rank": "Postua", "outlet": "Denda", @@ -395,7 +395,7 @@ "new_dashboard": { "system_status": { "title": "Sistema Egoera", - "issues_requiring_action": "{count, plural, one {# arazok} other {# arazok}} zure ekintza behar {count, plural, one {du} other {dute}}", + "issues_requiring_action": "{count, plural, one {# arazok} other {# arazok} zure ekintza behar {count, plural, one {du} other {dute}}", "all_clear": "Sistema guztiak ondo dabiltza", "never_run": "Inoiz exekutatu gabe", "action_needed_label": "ekintza behar", @@ -411,7 +411,7 @@ }, "pending_purchases": { "title": "Erosketa Zain", - "count": "{count, plural, one {# agindu} other {# agindu}} onarpenaren zai", + "count": "{count, plural, one {# agindu} other {# agindu} onarpenaren zai}", "no_pending": "Ez dago erosketa-agindu zain", "all_clear": "Ez dago erosketa-agindu onartzeko zain", "po_number": "EA #{number}", @@ -421,14 +421,14 @@ "view_details": "Xehetasunak Ikusi", "ai_reasoning": "IAk EA hau sortu zuen zeren:", "reasoning": { - "low_stock": "{ingredient} {days, plural, =0 {egun bat baino gutxiago} one {# egunean} other {# egunetan}} agortuko da", - "low_stock_detailed": "{count, plural, one {# osagai kritiko} other {# osagai kritiko}} arriskuan: {products}. Lehen agortze {days, plural, =0 {<1 egun} one {1 egun} other {# egun}}, {batches, plural, one {# lote} other {# lote}} ukituz. Galera potentziala: €{loss}", + "low_stock": "{ingredient} {days, plural, =0 {egun bat baino gutxiago} one {# egunean} other {# egunetan} agortuko da}", + "low_stock_detailed": "{count, plural, one {# osagai kritiko} other {# osagai kritiko} arriskuan: {products}. Lehen agortze {days, plural, =0 {<1 egun} one {1 egun} other {# egun}, {batches, plural, one {# lote} other {# lote} ukituz. Galera potentziala: €{loss}}", "demand_forecast": "{product} produktuaren eskaria %{increase} igotzea espero da" } }, "pending_deliveries": { "title": "Entrega Zain", - "count": "{count, plural, one {# entrega} other {# entrega}} gaur espero", + "count": "{count, plural, one {# entrega} other {# entrega} gaur espero}", "no_deliveries": "Ez dago entregarik gaur esperatzen", "all_clear": "Ez dago entregarik zain gaur", "overdue_section": "Atzeratutako Entregak", @@ -442,7 +442,7 @@ }, "production_status": { "title": "Ekoizpen Egoera", - "count": "{count, plural, one {# lote} other {# lote}} gaur", + "count": "{count, plural, one {# lote} other {# lote} gaur}", "no_production": "Ez dago ekoizpenik programatuta gaur", "all_clear": "Ez dago ekoizpenik programatuta gaur", "late_section": "Hasteko Atzeratua", @@ -492,7 +492,7 @@ "batch_delayed": "Lotearen Hasiera Atzeratuta", "generic": "Ekoizpen Alerta", "active": "Aktiboa", - "affected_orders": "{count, plural, one {# eskaera} other {# eskaera}} kaltetuak", + "affected_orders": "{count, plural, one {# eskaera} other {# eskaera} kaltetuak}", "delay_hours": "{hours}h atzerapena", "financial_impact": "€{amount} eragina", "urgent_in": "Presazkoa {hours}h-tan" diff --git a/frontend/src/locales/eu/help.json b/frontend/src/locales/eu/help.json index adeb0f0e..03474cb9 100644 --- a/frontend/src/locales/eu/help.json +++ b/frontend/src/locales/eu/help.json @@ -170,11 +170,6 @@ } ], "contact": { - "liveChat": { - "title": "Zuzeneko Txata", - "description": "Erantzun berehalakoa 9:00-21:00", - "action": "Hasi Txata" - }, "email": { "title": "Posta Elektronikoa", "description": "Erantzuna 4 ordu baino gutxiagoan", @@ -187,7 +182,6 @@ "action": "Ikusi Dokumentuak" }, "hours": { - "liveChat": "Astelehenetik ostiralera 9:00 - 21:00, Larunbatak 10:00 - 18:00", "email": "24/7 (erantzuna 4 orduen barruan lan orduetan)", "phone": "Astelehenetik ostiralera 10:00 - 19:00 (bezero aktiboak soilik)" } @@ -209,4 +203,4 @@ "action": "Irakurri Aholkuak" } } -} +} \ No newline at end of file diff --git a/frontend/src/locales/eu/models.json b/frontend/src/locales/eu/models.json index f37662a2..eeadd768 100644 --- a/frontend/src/locales/eu/models.json +++ b/frontend/src/locales/eu/models.json @@ -92,9 +92,9 @@ }, "messages": { - "training_started": "Entrenamentua hasi da {{name}}rako", + "training_started": "Entrenamentua hasi da {name}rako", "training_error": "Errorea entrenamentua hastean", - "retraining_started": "Berrentrenamendua hasi da {{name}}rako", + "retraining_started": "Berrentrenamendua hasi da {name}rako", "retraining_error": "Errorea eredua berrentrenatzean" } } diff --git a/frontend/src/locales/eu/onboarding.json b/frontend/src/locales/eu/onboarding.json index 09d11615..264122c6 100644 --- a/frontend/src/locales/eu/onboarding.json +++ b/frontend/src/locales/eu/onboarding.json @@ -243,8 +243,8 @@ "deployment": "Hedapena", "processing": "Prozesatzen..." }, - "estimated_time": "Aurreikusitako denbora: {{minutes}} minutu", - "estimated_time_remaining": "Geratzen den denbora aurreikusia: {{time}}", + "estimated_time": "Aurreikusitako denbora: {minutes} minutu", + "estimated_time_remaining": "Geratzen den denbora aurreikusia: {time}", "description": "AA modelo pertsonalizatu bat sortzen ari gara zure okindegiarentzat zure datu historikoen oinarrian.", "training_info": { "title": "Zer gertatzen da prestakuntzaren bitartean?", diff --git a/frontend/src/locales/eu/procurement.json b/frontend/src/locales/eu/procurement.json index a2c009a8..f9009542 100644 --- a/frontend/src/locales/eu/procurement.json +++ b/frontend/src/locales/eu/procurement.json @@ -115,10 +115,10 @@ "auto_approve": "🤖 Auto-onartua" }, "messages": { - "confirm_send": "Bidali {{po_number}} agindua hornitzaileari?", - "confirm_receive": "Berretsi {{po_number}} aginduaren harrera?", - "confirm_items": "Markatu artikuluak jasota {{po_number}} aginduarentzat?", - "confirm_complete": "Osatu {{po_number}} agindua?", - "cancel_reason": "Zergatik ezeztatu nahi duzu {{po_number}} agindua?" + "confirm_send": "Bidali {po_number} agindua hornitzaileari?", + "confirm_receive": "Berretsi {po_number} aginduaren harrera?", + "confirm_items": "Markatu artikuluak jasota {po_number} aginduarentzat?", + "confirm_complete": "Osatu {po_number} agindua?", + "cancel_reason": "Zergatik ezeztatu nahi duzu {po_number} agindua?" } } diff --git a/frontend/src/locales/eu/reasoning.json b/frontend/src/locales/eu/reasoning.json index 726978b0..c37de7fe 100644 --- a/frontend/src/locales/eu/reasoning.json +++ b/frontend/src/locales/eu/reasoning.json @@ -1,10 +1,10 @@ { "orchestration": { - "daily_summary": "{purchase_orders_count, plural, =0 {} =1 {1 erosketa agindu sortu} other {{purchase_orders_count} erosketa agindu sortu}}{purchase_orders_count, plural, =0 {} other { eta }}{production_batches_count, plural, =0 {ekoizpen loterik ez} =1 {1 ekoizpen lote programatu} other {{production_batches_count} ekoizpen lote programatu}}. {critical_items_count, plural, =0 {Guztia stockean.} =1 {Artikulu kritiko 1 arreta behar du} other {{critical_items_count} artikulu kritiko arreta behar dute}}{total_financial_impact_eur, select, 0 {} other { (€{total_financial_impact_eur} arriskuan)}}{min_depletion_hours, select, 0 {} other { - {min_depletion_hours}h stock amaitu arte}}." + "daily_summary": "{purchase_orders_count, plural, =0 {} =1 {1 erosketa agindu sortu} other {purchase_orders_count} erosketa agindu sortu}{purchase_orders_count, plural, =0 {} other { eta }{production_batches_count, plural, =0 {ekoizpen loterik ez} =1 {1 ekoizpen lote programatu} other {production_batches_count} ekoizpen lote programatu}. {critical_items_count, plural, =0 {Guztia stockean.} =1 {Artikulu kritiko 1 arreta behar du} other {critical_items_count} artikulu kritiko arreta behar dute}{total_financial_impact_eur, select, 0 {} other { (€{total_financial_impact_eur} arriskuan)}{min_depletion_hours, select, 0 {} other { - {min_depletion_hours}h stock amaitu arte}.}}" }, "purchaseOrder": { "low_stock_detection": "{supplier_name}-rentzat stock baxua. {product_names_joined}-ren egungo stocka {days_until_stockout} egunetan amaituko da.", - "low_stock_detection_detailed": "{critical_product_count, plural, =1 {{critical_products_0} {min_depletion_hours} ordutan amaituko da} other {{critical_product_count} produktu kritiko urri}}. {supplier_name}-ren {supplier_lead_time_days} eguneko entregarekin, {order_urgency, select, critical {BEREHALA} urgent {GAUR} important {laster} other {orain}} eskatu behar dugu {affected_batches_count, plural, =0 {ekoizpen atzerapenak} =1 {{affected_batches_0} lotearen etetea} other {{affected_batches_count} loteen etetea}} saihesteko{potential_loss_eur, select, 0 {} other { (€{potential_loss_eur} arriskuan)}}.", + "low_stock_detection_detailed": "{critical_product_count, plural, =1 {critical_products_0} {min_depletion_hours} ordutan amaituko da} other {critical_product_count} produktu kritiko urri}. {supplier_name}-ren {supplier_lead_time_days} eguneko entregarekin, {order_urgency, select, critical {BEREHALA} urgent {GAUR} important {laster} other {orain} eskatu behar dugu {affected_batches_count, plural, =0 {ekoizpen atzerapenak} =1 {affected_batches_0} lotearen etetea} other {affected_batches_count} loteen etetea} saihesteko{potential_loss_eur, select, 0 {} other { (€{potential_loss_eur} arriskuan)}.", "forecast_demand": "{supplier_name}-ren {product_names_joined}-rentzat {forecast_period_days} eguneko eskaera aurreikuspenean oinarritutako eskaera programatua.", "safety_stock_replenishment": "{supplier_name}-ren {product_names_joined}-rentzat segurtasun stockaren birjartzea.", "supplier_contract": "{supplier_name}-rekin kontratuaren arabera programatutako eskaera.", diff --git a/frontend/src/locales/eu/setup_wizard.json b/frontend/src/locales/eu/setup_wizard.json index 08616cea..5e1db132 100644 --- a/frontend/src/locales/eu/setup_wizard.json +++ b/frontend/src/locales/eu/setup_wizard.json @@ -36,7 +36,7 @@ "add_another": "Beste Hornitzaile Bat Gehitu", "manage_products": "Produktuak Kudeatu", "products": "produktuak", - "products_for": "{{name}}-(r)entzako produktuak", + "products_for": "{name}-(r)entzako produktuak", "add_products": "Produktuak Gehitu", "no_products_available": "Ez dago produkturik eskuragarri", "select_products": "Produktuak Aukeratu", @@ -115,6 +115,7 @@ "expiration_past": "Iraungitze data iraganean dago", "expiring_soon": "Abisua: Osagai hau laster iraungitzen da!" }, + "batch_label": "Lotea", "templates": { "basic-bakery": "Oinarrizko Okindegi Osagaiak", "basic-bakery-desc": "Okindegi orokorrentzako funtsezko osagaiak", @@ -130,6 +131,9 @@ "why": "Errezetak zure inbentarioa ekoizpenarekin konektatzen dute. Sistemak elementu bakoitzeko kostu zehatzak kalkulatuko ditu, osagaien kontsumoa jarraituko du eta menuko errentagarritasuna optimizatzen lagunduko dizu.", "quick_start": "Errezeta Txantiloiak", "quick_start_desc": "Hasi frogatutako errezetekin eta pertsonalizatu zure beharretara", + "template_ingredients": "Osagaiak:", + "template_instructions": "Argibideak:", + "template_tips": "Aholkuak:", "category": { "breads": "Ogiak", "pastries": "Gozogintza", @@ -219,17 +223,29 @@ "fields": { "name": "Izen Osoa", "email": "Posta Elektroniko Helbidea", + "password": "Pasahitza", + "confirm_password": "Pasahitza Berretsi", + "phone": "Telefonoa", "role": "Rola" }, "placeholders": { "name": "adib., María García", - "email": "adib., maria@okindegi.eus" + "email": "adib., maria@okindegi.eus", + "password": "••••••••", + "confirm_password": "••••••••", + "phone": "+34 600 000 000" }, + "email_hint": "Hau erabiltzaile-izena izango da saioa hasteko", + "password_hint": "Gutxienez 8 karaktere", "errors": { "name_required": "Izena beharrezkoa da", "email_required": "Posta beharrezkoa da", "email_invalid": "Posta formatu baliogabea", - "email_duplicate": "Posta elektroniko hau dagoeneko gehituta dago" + "email_duplicate": "Posta elektroniko hau dagoeneko gehituta dago", + "password_required": "Pasahitza beharrezkoa da", + "password_min_length": "Pasahitzak gutxienez 8 karaktere izan behar ditu", + "confirm_password_required": "Mesedez, pasahitza berretsi", + "passwords_mismatch": "Pasahitzak ez datoz bat" } }, "review": { @@ -250,7 +266,7 @@ "quality_title": "Kalitate Kontrol Txantiloiak", "required": "Nahitaezkoa", "ready_title": "Zure Okindegi Prest Dago!", - "ready_message": "Arrakastaz konfiguratu dituzu {{suppliers}} hornitzaile, {{ingredients}} osagai eta {{recipes}} errezeta. Egin klik 'Konfigurazioa Osatu'-n amaitzeko eta sistema erabiltzen hasteko.", + "ready_message": "Arrakastaz konfiguratu dituzu {suppliers} hornitzaile, {ingredients} osagai eta {recipes} errezeta. Egin klik 'Konfigurazioa Osatu'-n amaitzeko eta sistema erabiltzen hasteko.", "help": "Aldaketak egin behar dituzu? Erabili \"Atzera\" botoia edozein urratsera itzultzeko." }, "completion": { diff --git a/frontend/src/locales/eu/suppliers.json b/frontend/src/locales/eu/suppliers.json index 0eb75ea1..b44128d7 100644 --- a/frontend/src/locales/eu/suppliers.json +++ b/frontend/src/locales/eu/suppliers.json @@ -213,7 +213,7 @@ }, "delete": { "title": "Produktua Kendu Hornitzailetik", - "description": "Ziur zaude {{product}} hornitzaile honen prezioen zerrendatik kendu nahi duzula?" + "description": "Ziur zaude {product} hornitzaile honen prezioen zerrendatik kendu nahi duzula?" } }, "delete": { diff --git a/frontend/src/locales/index.ts b/frontend/src/locales/index.ts index 27dca864..4a408852 100644 --- a/frontend/src/locales/index.ts +++ b/frontend/src/locales/index.ts @@ -25,6 +25,7 @@ import blogEs from './es/blog.json'; import alertsEs from './es/alerts.json'; import onboardingEs from './es/onboarding.json'; import setupWizardEs from './es/setup_wizard.json'; +import contactEs from './es/contact.json'; // English translations import commonEn from './en/common.json'; @@ -53,6 +54,7 @@ import blogEn from './en/blog.json'; import alertsEn from './en/alerts.json'; import onboardingEn from './en/onboarding.json'; import setupWizardEn from './en/setup_wizard.json'; +import contactEn from './en/contact.json'; // Basque translations import commonEu from './eu/common.json'; @@ -81,6 +83,7 @@ import blogEu from './eu/blog.json'; import alertsEu from './eu/alerts.json'; import onboardingEu from './eu/onboarding.json'; import setupWizardEu from './eu/setup_wizard.json'; +import contactEu from './eu/contact.json'; // Translation resources by language export const resources = { @@ -111,6 +114,7 @@ export const resources = { alerts: alertsEs, onboarding: onboardingEs, setup_wizard: setupWizardEs, + contact: contactEs, }, en: { common: commonEn, @@ -139,6 +143,7 @@ export const resources = { alerts: alertsEn, onboarding: onboardingEn, setup_wizard: setupWizardEn, + contact: contactEn, }, eu: { common: commonEu, @@ -167,6 +172,7 @@ export const resources = { alerts: alertsEu, onboarding: onboardingEu, setup_wizard: setupWizardEu, + contact: contactEu, }, }; @@ -203,7 +209,7 @@ export const languageConfig = { }; // Namespaces available in translations -export const namespaces = ['common', 'auth', 'inventory', 'foodSafety', 'suppliers', 'orders', 'recipes', 'errors', 'dashboard', 'production', 'equipment', 'landing', 'settings', 'ajustes', 'reasoning', 'wizards', 'subscription', 'purchase_orders', 'help', 'features', 'about', 'demo', 'blog', 'alerts', 'onboarding', 'setup_wizard'] as const; +export const namespaces = ['common', 'auth', 'inventory', 'foodSafety', 'suppliers', 'orders', 'recipes', 'errors', 'dashboard', 'production', 'equipment', 'landing', 'settings', 'ajustes', 'reasoning', 'wizards', 'subscription', 'purchase_orders', 'help', 'features', 'about', 'demo', 'blog', 'alerts', 'onboarding', 'setup_wizard', 'contact'] as const; export type Namespace = typeof namespaces[number]; // Helper function to get language display name diff --git a/frontend/src/pages/public/ContactPage.tsx b/frontend/src/pages/public/ContactPage.tsx index 808e4f32..ddb5fead 100644 --- a/frontend/src/pages/public/ContactPage.tsx +++ b/frontend/src/pages/public/ContactPage.tsx @@ -24,7 +24,7 @@ interface ContactMethod { } const ContactPage: React.FC = () => { - const { t } = useTranslation(); + const { t } = useTranslation(['contact', 'common']); const [formState, setFormState] = useState({ name: '', email: '', @@ -37,35 +37,27 @@ const ContactPage: React.FC = () => { const [submitStatus, setSubmitStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle'); const contactMethods: ContactMethod[] = [ - { - id: 'chat', - title: 'Chat en Vivo', - description: 'Respuesta inmediata', - detail: 'Lunes a Viernes: 9:00 - 21:00 CET', - icon: MessageSquare, - link: '#chat', - }, { id: 'email', - title: 'Email', - description: 'soporte@panaderia-ia.com', - detail: 'Respuesta en menos de 4 horas', + title: t('methods.email.title'), + description: t('methods.email.description'), + detail: t('methods.email.detail'), icon: Mail, - link: 'mailto:soporte@panaderia-ia.com', + link: `mailto:${t('methods.email.description')}`, }, { id: 'phone', - title: 'Teléfono', - description: '+34 XXX XXX XXX', - detail: 'Lunes a Viernes: 10:00 - 19:00 CET', + title: t('methods.phone.title'), + description: t('methods.phone.description'), + detail: t('methods.phone.detail'), icon: Phone, - link: 'tel:+34XXXXXXXXX', + link: `tel:${t('methods.phone.description').replace(/\s/g, '')}`, }, { id: 'office', - title: 'Oficina', - description: 'Barcelona, España', - detail: 'Con cita previa', + title: t('methods.office.title'), + description: t('methods.office.description'), + detail: t('methods.office.detail'), icon: MapPin, }, ]; @@ -118,15 +110,15 @@ const ContactPage: React.FC = () => {
- - Contacto y Soporte + + {t('hero.badge')}

- Estamos Aquí Para - Ayudarte + {t('hero.title')} + {t('hero.title_accent')}

- ¿Tienes preguntas? ¿Necesitas ayuda? Nuestro equipo está listo para asistirte + {t('hero.subtitle')}

@@ -137,14 +129,14 @@ const ContactPage: React.FC = () => {

- Múltiples Formas de Contactar + {t('methods.title')}

- Elige el método que más te convenga + {t('methods.subtitle')}

-
+
{contactMethods.map((method) => { const ContactIcon = method.icon; const content = ( @@ -194,10 +186,10 @@ const ContactPage: React.FC = () => {

- Envíanos un Mensaje + {t('form.title')}

- Completa el formulario y te responderemos lo antes posible + {t('form.subtitle')}

@@ -207,7 +199,7 @@ const ContactPage: React.FC = () => {

- ¡Mensaje enviado! Te responderemos pronto. + {t('form.success.title')} {t('form.success.message')}

)} @@ -216,7 +208,7 @@ const ContactPage: React.FC = () => {

- Error al enviar. Por favor, inténtalo de nuevo. + {t('form.error.title')} {t('form.error.message')}

)} @@ -225,7 +217,7 @@ const ContactPage: React.FC = () => { {/* Name */}
{ onChange={handleChange} required className="w-full px-4 py-3 bg-[var(--bg-secondary)] border border-[var(--border-primary)] rounded-xl text-[var(--text-primary)] placeholder:text-[var(--text-tertiary)] focus:outline-none focus:border-[var(--color-primary)] transition-colors" - placeholder="Tu nombre" + placeholder={t('form.fields.name_placeholder')} />
{/* Email */}
{ onChange={handleChange} required className="w-full px-4 py-3 bg-[var(--bg-secondary)] border border-[var(--border-primary)] rounded-xl text-[var(--text-primary)] placeholder:text-[var(--text-tertiary)] focus:outline-none focus:border-[var(--color-primary)] transition-colors" - placeholder="tu@email.com" + placeholder={t('form.fields.email_placeholder')} />
{/* Phone */}
{ value={formState.phone} onChange={handleChange} className="w-full px-4 py-3 bg-[var(--bg-secondary)] border border-[var(--border-primary)] rounded-xl text-[var(--text-primary)] placeholder:text-[var(--text-tertiary)] focus:outline-none focus:border-[var(--color-primary)] transition-colors" - placeholder="+34 XXX XXX XXX" + placeholder={t('form.fields.phone_placeholder')} />
{/* Bakery Name */}
{ value={formState.bakeryName} onChange={handleChange} className="w-full px-4 py-3 bg-[var(--bg-secondary)] border border-[var(--border-primary)] rounded-xl text-[var(--text-primary)] placeholder:text-[var(--text-tertiary)] focus:outline-none focus:border-[var(--color-primary)] transition-colors" - placeholder="Panadería Ejemplo" + placeholder={t('form.fields.bakery_name_placeholder')} />
{/* Type */}
{/* Subject */}
{ onChange={handleChange} required className="w-full px-4 py-3 bg-[var(--bg-secondary)] border border-[var(--border-primary)] rounded-xl text-[var(--text-primary)] placeholder:text-[var(--text-tertiary)] focus:outline-none focus:border-[var(--color-primary)] transition-colors" - placeholder="¿En qué podemos ayudarte?" + placeholder={t('form.fields.subject_placeholder')} />
@@ -329,7 +321,7 @@ const ContactPage: React.FC = () => { {/* Message */}