feat(frontend): add PL/EN i18n using @inlang/paraglide-js v2

- Install @inlang/paraglide-js v2 with Vite plugin and paraglideMiddleware hook
- Add messages/pl.json and messages/en.json with ~400 translation keys
- Create project.inlang/settings.json (PL as base locale)
- Add LanguageSwitcher component (cookie-based, no URL prefix needed)
- Replace all hardcoded strings across 14 pages/components with m.*() calls
- ProductForm uses derived label maps for all enum types (category, texture, etc.)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Piotr Oleszczyk 2026-03-01 13:20:34 +01:00
parent 9524e4df54
commit 99584521a1
22 changed files with 1742 additions and 612 deletions

437
frontend/messages/en.json Normal file
View file

@ -0,0 +1,437 @@
{
"nav_dashboard": "Dashboard",
"nav_products": "Products",
"nav_routines": "Routines",
"nav_grooming": "Grooming",
"nav_medications": "Medications",
"nav_labResults": "Lab Results",
"nav_skin": "Skin",
"nav_appName": "innercontext",
"nav_appSubtitle": "personal health & skincare",
"common_save": "Save",
"common_cancel": "Cancel",
"common_add": "Add",
"common_edit": "Edit",
"common_delete": "Delete",
"common_saved": "Saved.",
"common_select": "Select",
"common_unknown": "Unknown",
"common_yes": "Yes",
"common_no": "No",
"common_unknown_value": "Unknown",
"common_optional_notes": "optional",
"common_steps": "steps",
"dashboard_title": "Dashboard",
"dashboard_subtitle": "Your recent health & skincare overview",
"dashboard_latestSnapshot": "Latest Skin Snapshot",
"dashboard_recentRoutines": "Recent Routines",
"dashboard_noSnapshots": "No skin snapshots yet.",
"dashboard_noRoutines": "No routines in the past 2 weeks.",
"products_title": "Products",
"products_count": "{count} products",
"products_addNew": "+ Add product",
"products_noProducts": "No products found.",
"products_filterAll": "All",
"products_filterOwned": "Owned",
"products_filterUnowned": "Not owned",
"products_colName": "Name",
"products_colBrand": "Brand",
"products_colTargets": "Targets",
"products_colTime": "Time",
"products_newTitle": "New Product",
"products_backToList": "← Products",
"products_createProduct": "Create product",
"products_saveChanges": "Save changes",
"products_deleteProduct": "Delete product",
"products_confirmDelete": "Delete this product?",
"products_noInventory": "No inventory packages.",
"inventory_title": "Inventory packages ({count})",
"inventory_addPackage": "+ Add package",
"inventory_packageAdded": "Package added.",
"inventory_packageUpdated": "Package updated.",
"inventory_packageDeleted": "Package deleted.",
"inventory_alreadyOpened": "Already opened",
"inventory_openedDate": "Opened date",
"inventory_finishedDate": "Finished date",
"inventory_expiryDate": "Expiry date",
"inventory_currentWeight": "Current weight (g)",
"inventory_lastWeighed": "Last weighed",
"inventory_notes": "Notes",
"inventory_badgeOpen": "Open",
"inventory_badgeSealed": "Sealed",
"inventory_badgeFinished": "Finished",
"inventory_exp": "Exp:",
"inventory_opened": "Opened:",
"inventory_finished": "Finished:",
"inventory_remaining": "g remaining",
"inventory_weighed": "Weighed:",
"inventory_confirmDelete": "Delete this package?",
"routines_title": "Routines",
"routines_count": "{count} routines (last 30 days)",
"routines_suggestAI": "Suggest AI routine",
"routines_addNew": "+ New routine",
"routines_noRoutines": "No routines found.",
"routines_newTitle": "New Routine",
"routines_backToList": "← Routines",
"routines_detailsTitle": "Routine details",
"routines_date": "Date *",
"routines_amOrPm": "AM or PM *",
"routines_notes": "Notes",
"routines_notesPlaceholder": "Optional notes",
"routines_createRoutine": "Create routine",
"routines_deleteRoutine": "Delete routine",
"routines_confirmDelete": "Delete this routine?",
"routines_steps": "Steps ({count})",
"routines_addStep": "+ Add step",
"routines_addStepTitle": "Add step",
"routines_product": "Product",
"routines_selectProduct": "Select product",
"routines_dose": "Dose",
"routines_dosePlaceholder": "e.g. 2 pumps",
"routines_region": "Region",
"routines_regionPlaceholder": "e.g. face",
"routines_addStepBtn": "Add step",
"routines_unknownStep": "Unknown step",
"routines_noSteps": "No steps yet.",
"grooming_title": "Grooming Schedule",
"grooming_backToRoutines": "← Routines",
"grooming_addEntry": "+ Add entry",
"grooming_entryAdded": "Entry added.",
"grooming_entryUpdated": "Entry updated.",
"grooming_entryDeleted": "Entry deleted.",
"grooming_dayOfWeek": "Day of week",
"grooming_action": "Action",
"grooming_notesOptional": "Notes (optional)",
"grooming_notesPlaceholder": "e.g. every 2 weeks",
"grooming_noEntries": "No entries yet. Click \"+ Add entry\" to get started.",
"grooming_confirmDelete": "Delete this entry?",
"grooming_actionShavingRazor": "Razor shaving",
"grooming_actionShavingOneblade": "OneBlade shaving",
"grooming_actionDermarolling": "Dermarolling",
"grooming_dayMonday": "Monday",
"grooming_dayTuesday": "Tuesday",
"grooming_dayWednesday": "Wednesday",
"grooming_dayThursday": "Thursday",
"grooming_dayFriday": "Friday",
"grooming_daySaturday": "Saturday",
"grooming_daySunday": "Sunday",
"suggest_title": "AI Routine Suggestion",
"suggest_backToRoutines": "← Routines",
"suggest_singleTab": "Single routine",
"suggest_batchTab": "Batch / Vacation",
"suggest_singleParams": "Parameters",
"suggest_date": "Date",
"suggest_timeOfDay": "Time of day",
"suggest_contextLabel": "Additional context for AI",
"suggest_contextOptional": "(optional)",
"suggest_contextPlaceholder": "e.g. party night, focusing on hydration...",
"suggest_generateBtn": "Generate suggestion",
"suggest_generating": "Generating…",
"suggest_proposalTitle": "Suggestion",
"suggest_saveRoutine": "Save routine",
"suggest_saving": "Saving…",
"suggest_regenerate": "Regenerate",
"suggest_batchRange": "Date range",
"suggest_fromDate": "From",
"suggest_toDate": "To (max 14 days)",
"suggest_batchContextLabel": "Context / trip purpose",
"suggest_batchContextPlaceholder": "e.g. sunny trip to Italy, active mountain vacation...",
"suggest_generatePlan": "Generate plan",
"suggest_generatingPlan": "Generating plan…",
"suggest_planTitle": "Plan ({count} days)",
"suggest_saveAllRoutines": "Save all routines",
"suggest_amSteps": "steps",
"suggest_pmSteps": "steps",
"suggest_noAmSteps": "No AM steps.",
"suggest_noPmSteps": "No PM steps.",
"suggest_errorDefault": "Error generating suggestion.",
"suggest_errorBatch": "Error generating plan.",
"suggest_errorSave": "Error saving.",
"suggest_amMorning": "AM (morning)",
"suggest_pmEvening": "PM (evening)",
"medications_title": "Medications",
"medications_count": "{count} entries",
"medications_addNew": "+ Add medication",
"medications_newTitle": "New medication",
"medications_kind": "Kind",
"medications_productName": "Product name *",
"medications_productNamePlaceholder": "e.g. Vitamin D3",
"medications_activeSubstance": "Active substance",
"medications_activeSubstancePlaceholder": "e.g. cholecalciferol",
"medications_notes": "Notes",
"medications_added": "Medication added.",
"medications_usages": "{count} usages",
"medications_noMedications": "No medications recorded.",
"medications_kindPrescription": "Prescription",
"medications_kindOtc": "OTC",
"medications_kindSupplement": "Supplement",
"medications_kindHerbal": "Herbal",
"medications_kindOther": "Other",
"labResults_title": "Lab Results",
"labResults_count": "{count} results",
"labResults_addNew": "+ Add result",
"labResults_newTitle": "New lab result",
"labResults_flagFilter": "Flag:",
"labResults_flagAll": "All",
"labResults_flagNone": "None",
"labResults_date": "Date *",
"labResults_loincCode": "LOINC code *",
"labResults_testName": "Test name",
"labResults_testNamePlaceholder": "e.g. Hemoglobin",
"labResults_lab": "Lab",
"labResults_labPlaceholder": "e.g. LabCorp",
"labResults_value": "Value",
"labResults_unit": "Unit",
"labResults_unitPlaceholder": "e.g. g/dL",
"labResults_flag": "Flag",
"labResults_added": "Result added.",
"labResults_colDate": "Date",
"labResults_colTest": "Test",
"labResults_colLoinc": "LOINC",
"labResults_colValue": "Value",
"labResults_colFlag": "Flag",
"labResults_colLab": "Lab",
"labResults_noResults": "No lab results found.",
"skin_title": "Skin Snapshots",
"skin_count": "{count} snapshots",
"skin_addNew": "+ Add snapshot",
"skin_aiAnalysisTitle": "AI analysis from photos",
"skin_aiUploadText": "Upload 13 photos of your skin. AI will pre-fill the form fields below.",
"skin_analyzePhotos": "Analyze photos",
"skin_analyzing": "Analyzing…",
"skin_newSnapshotTitle": "New skin snapshot",
"skin_date": "Date *",
"skin_overallState": "Overall state",
"skin_texture": "Texture",
"skin_skinType": "Skin type",
"skin_barrierState": "Barrier state",
"skin_hydration": "Hydration (15)",
"skin_sensitivity": "Sensitivity (15)",
"skin_sebumTzone": "Sebum T-zone (15)",
"skin_sebumCheeks": "Sebum cheeks (15)",
"skin_activeConcerns": "Active concerns (comma-separated)",
"skin_activeConcernsPlaceholder": "acne, redness, dehydration",
"skin_notes": "Notes",
"skin_addSnapshot": "Add snapshot",
"skin_snapshotAdded": "Snapshot added.",
"skin_snapshotUpdated": "Snapshot updated.",
"skin_snapshotDeleted": "Snapshot deleted.",
"skin_noSnapshots": "No skin snapshots yet.",
"skin_hydrationLabel": "Hydration",
"skin_sensitivityLabel": "Sensitivity",
"skin_barrierLabel": "Barrier",
"skin_stateExcellent": "excellent",
"skin_stateGood": "good",
"skin_stateFair": "fair",
"skin_statePoor": "poor",
"skin_textureSmooth": "smooth",
"skin_textureRough": "rough",
"skin_textureFlaky": "flaky",
"skin_textureBumpy": "bumpy",
"skin_barrierIntact": "intact",
"skin_barrierMildly": "mildly compromised",
"skin_barrierCompromised": "compromised",
"skin_typeDry": "dry",
"skin_typeOily": "oily",
"skin_typeCombination": "combination",
"skin_typeSensitive": "sensitive",
"skin_typeNormal": "normal",
"skin_typeAcneProne": "acne prone",
"productForm_aiPrefill": "AI pre-fill",
"productForm_aiPrefillText": "Paste product description from a website, ingredient list, or other text. AI will fill in available fields — you can review and correct before saving.",
"productForm_pasteText": "Paste product description, INCI ingredients here...",
"productForm_parseWithAI": "Fill fields (AI)",
"productForm_parsing": "Processing…",
"productForm_basicInfo": "Basic info",
"productForm_name": "Name *",
"productForm_namePlaceholder": "e.g. Hydro Boost Water Gel",
"productForm_brand": "Brand *",
"productForm_brandPlaceholder": "e.g. Neutrogena",
"productForm_lineName": "Line / series",
"productForm_lineNamePlaceholder": "e.g. Hydro Boost",
"productForm_url": "URL",
"productForm_sku": "SKU",
"productForm_skuPlaceholder": "e.g. NTR-HB-50",
"productForm_barcode": "Barcode / EAN",
"productForm_barcodePlaceholder": "e.g. 3614273258975",
"productForm_classification": "Classification",
"productForm_category": "Category *",
"productForm_selectCategory": "Select category",
"productForm_time": "Time *",
"productForm_timeOptions": "AM / PM / Both",
"productForm_timeBoth": "Both",
"productForm_leaveOn": "Leave-on *",
"productForm_leaveOnYes": "Yes (leave-on)",
"productForm_leaveOnNo": "No (rinse-off)",
"productForm_texture": "Texture",
"productForm_selectTexture": "Select texture",
"productForm_absorptionSpeed": "Absorption speed",
"productForm_selectSpeed": "Select speed",
"productForm_skinProfile": "Skin profile",
"productForm_recommendedFor": "Recommended for skin types",
"productForm_targetConcerns": "Target concerns",
"productForm_contraindications": "Contraindications (one per line)",
"productForm_contraindicationsPlaceholder": "e.g. active rosacea flares",
"productForm_ingredients": "Ingredients",
"productForm_inciList": "INCI list (one ingredient per line)",
"productForm_activeIngredients": "Active ingredients",
"productForm_addActive": "+ Add active",
"productForm_noActives": "No actives added yet.",
"productForm_activeName": "Name",
"productForm_activePercent": "%",
"productForm_activeStrength": "Strength",
"productForm_activeIrritation": "Irritation",
"productForm_activeFunctions": "Functions",
"productForm_effectProfile": "Effect profile (05)",
"productForm_interactions": "Interactions",
"productForm_synergizesWith": "Synergizes with (one per line)",
"productForm_incompatibleWith": "Incompatible with",
"productForm_addIncompatibility": "+ Add incompatibility",
"productForm_noIncompatibilities": "No incompatibilities added.",
"productForm_incompTarget": "Target ingredient",
"productForm_incompScope": "Scope",
"productForm_incompReason": "Reason (optional)",
"productForm_incompReasonPlaceholder": "e.g. reduces efficacy",
"productForm_incompScopeSelect": "Select…",
"productForm_contextRules": "Context rules",
"productForm_ctxAfterShaving": "Safe after shaving",
"productForm_ctxAfterAcids": "Safe after acids",
"productForm_ctxAfterRetinoids": "Safe after retinoids",
"productForm_ctxCompromisedBarrier": "Safe with compromised barrier",
"productForm_ctxLowUvOnly": "Low UV only (evening/covered)",
"productForm_productDetails": "Product details",
"productForm_priceTier": "Price tier",
"productForm_selectTier": "Select tier",
"productForm_sizeMl": "Size (ml)",
"productForm_fullWeightG": "Full weight (g)",
"productForm_emptyWeightG": "Empty weight (g)",
"productForm_paoMonths": "PAO (months)",
"productForm_phMin": "pH min",
"productForm_phMax": "pH max",
"productForm_usageNotes": "Usage notes",
"productForm_usageNotesPlaceholder": "e.g. Apply to damp skin, avoid eye area",
"productForm_safetyFlags": "Safety flags",
"productForm_fragranceFree": "Fragrance-free",
"productForm_essentialOilsFree": "Essential oils-free",
"productForm_alcoholDenatFree": "Alcohol denat-free",
"productForm_pregnancySafe": "Pregnancy safe",
"productForm_usageConstraints": "Usage constraints",
"productForm_minIntervalHours": "Min interval (hours)",
"productForm_maxFrequencyPerWeek": "Max uses per week",
"productForm_isMedication": "Is medication",
"productForm_isTool": "Is tool (e.g. dermaroller)",
"productForm_needleLengthMm": "Needle length (mm, tools only)",
"productForm_personalNotes": "Personal notes",
"productForm_repurchaseIntent": "Repurchase intent",
"productForm_toleranceNotes": "Tolerance notes",
"productForm_toleranceNotesPlaceholder": "e.g. Causes mild stinging, fine after 2 weeks",
"productForm_categoryCleanser": "Cleanser",
"productForm_categoryToner": "Toner",
"productForm_categoryEssence": "Essence",
"productForm_categorySerum": "Serum",
"productForm_categoryMoisturizer": "Moisturizer",
"productForm_categorySpf": "SPF",
"productForm_categoryMask": "Mask",
"productForm_categoryExfoliant": "Exfoliant",
"productForm_categoryHairTreatment": "Hair treatment",
"productForm_categoryTool": "Tool",
"productForm_categorySpotTreatment": "Spot treatment",
"productForm_categoryOil": "Oil",
"productForm_textureWatery": "Watery",
"productForm_textureGel": "Gel",
"productForm_textureEmulsion": "Emulsion",
"productForm_textureCream": "Cream",
"productForm_textureOil": "Oil",
"productForm_textureBalm": "Balm",
"productForm_textureFoam": "Foam",
"productForm_textureFluid": "Fluid",
"productForm_absorptionVeryFast": "Very fast",
"productForm_absorptionFast": "Fast",
"productForm_absorptionModerate": "Moderate",
"productForm_absorptionSlow": "Slow",
"productForm_absorptionVerySlow": "Very slow",
"productForm_priceBudget": "Budget",
"productForm_priceMid": "Mid",
"productForm_pricePremium": "Premium",
"productForm_priceLuxury": "Luxury",
"productForm_skinTypeDry": "dry",
"productForm_skinTypeOily": "oily",
"productForm_skinTypeCombination": "combination",
"productForm_skinTypeSensitive": "sensitive",
"productForm_skinTypeNormal": "normal",
"productForm_skinTypeAcneProne": "acne prone",
"productForm_concernAcne": "acne",
"productForm_concernRosacea": "rosacea",
"productForm_concernHyperpigmentation": "hyperpigmentation",
"productForm_concernAging": "aging",
"productForm_concernDehydration": "dehydration",
"productForm_concernRedness": "redness",
"productForm_concernDamagedBarrier": "damaged barrier",
"productForm_concernPoreVisibility": "pore visibility",
"productForm_concernUnevenTexture": "uneven texture",
"productForm_concernHairGrowth": "hair growth",
"productForm_concernSebumExcess": "sebum excess",
"productForm_fnHumectant": "humectant",
"productForm_fnEmollient": "emollient",
"productForm_fnOcclusive": "occlusive",
"productForm_fnExfoliantAha": "AHA exfoliant",
"productForm_fnExfoliantBha": "BHA exfoliant",
"productForm_fnExfoliantPha": "PHA exfoliant",
"productForm_fnRetinoid": "retinoid",
"productForm_fnAntioxidant": "antioxidant",
"productForm_fnSoothing": "soothing",
"productForm_fnBarrierSupport": "barrier support",
"productForm_fnBrightening": "brightening",
"productForm_fnAntiAcne": "anti-acne",
"productForm_fnCeramide": "ceramide",
"productForm_fnNiacinamide": "niacinamide",
"productForm_fnSunscreen": "sunscreen",
"productForm_fnPeptide": "peptide",
"productForm_fnHairGrowth": "hair growth stimulant",
"productForm_fnPrebiotic": "prebiotic",
"productForm_fnVitaminC": "vitamin C",
"productForm_fnAntiAging": "anti-aging",
"productForm_scopeSameStep": "same step",
"productForm_scopeSameDay": "same day",
"productForm_scopeSamePeriod": "same period",
"productForm_strengthLow": "1 Low",
"productForm_strengthMedium": "2 Medium",
"productForm_strengthHigh": "3 High",
"productForm_effectHydrationImmediate": "Hydration (immediate)",
"productForm_effectHydrationLongTerm": "Hydration (long term)",
"productForm_effectBarrierRepair": "Barrier repair",
"productForm_effectSoothing": "Soothing",
"productForm_effectExfoliation": "Exfoliation",
"productForm_effectRetinoid": "Retinoid activity",
"productForm_effectIrritation": "Irritation risk",
"productForm_effectComedogenic": "Comedogenic risk",
"productForm_effectBarrierDisruption": "Barrier disruption risk",
"productForm_effectDryness": "Dryness risk",
"productForm_effectBrightening": "Brightening",
"productForm_effectAntiAcne": "Anti-acne",
"productForm_effectAntiAging": "Anti-aging",
"lang_pl": "PL",
"lang_en": "EN"
}