/** * French UI strings of the health module (CONVENTIONS C5.3). * Code stays English, every user-facing label lives here. */ export const S = { module: { title: "Santé", }, nav: { weight: "Poids & Objectif", nutrition: "Nutrition", activity: "Activité & Sport", energy: "Balance énergétique", }, actions: { add: "Ajouter", addWeight: "+ Ajouter une pesée", addFood: "+ Ajouter un aliment", addWorkout: "+ Ajouter une séance", addMeasurement: "+ Ajouter des mensurations", save: "Enregistrer", cancel: "Annuler", edit: "Modifier", delete: "Supprimer", close: "Fermer", today: "Aujourd'hui", replace: "Remplacer", addAnyway: "Ajouter quand même", addAndContinue: "Ajouter et continuer", resetFilters: "Réinitialiser les filtres", importCsv: "Importer un CSV", importFoodvisor: "Importer Foodvisor", seeImports: "Voir les imports", goToWeight: "Aller à Poids", goToNutrition: "Aller à Nutrition", noteWeighIn: "Noter ma pesée", noteWorkout: "Noter ma séance", editGoal: "Modifier l'objectif", useThisTdee: "Utiliser cette valeur comme TDEE", }, common: { loading: "Chargement…", none: "—", date: "Date", time: "Heure", note: "Note", source: "Source", total: "Total", average: "Moyenne", week: "Semaine", day: "Jour", kcal: "kcal", actionsColumn: "Actions", errorTitle: "Impossible de charger ces données", retry: "Réessayer", deleteConfirmTitle: "Supprimer cet élément ?", deleteConfirmMessage: "Cette action est irréversible.", noDataOnPeriod: "Pas de données sur cette période", widenPeriod: "Élargir la période", optional: "optionnel", }, errors: { weightRange: "Le poids doit être compris entre 20 et 300 kg.", required: "Ce champ est obligatoire.", invalidNumber: "Valeur numérique invalide.", invalidDuration: "Durée invalide (format hh:mm).", positive: "La valeur doit être positive.", }, /* ---------------------------------------------------------------- */ /* Poids & Objectif */ /* ---------------------------------------------------------------- */ weight: { title: "Poids & Objectif", kpi: { current: "Poids actuel", trend: "Tendance (EMA)", weeklyRate: "Rythme hebdo", bmi: "IMC", goal: "Objectif", projection: "Atteinte estimée", adherence: "Assiduité 30 j", }, charts: { evolution: "Évolution du poids", weeklyRate: "Rythme hebdomadaire", bmi: "IMC", measurements: "Mensurations", adherence: "Calendrier des pesées", }, series: { raw: "Pesées", trend: "Tendance", projection: "Projection", goal: "Objectif", rate: "Rythme", }, table: { title: "Historique des pesées", weight: "Poids", trend: "Tendance", variation: "Variation", }, goalCard: { title: "Objectif", none: "Aucun objectif défini.", progress: "Progression", start: "Départ", target: "Objectif", remaining: "Reste", }, modal: { title: "Ajouter une pesée", editTitle: "Modifier la pesée", weightLabel: "Poids (kg)", dateLabel: "Date", timeLabel: "Heure", noteLabel: "Note", notePlaceholder: "ex. après le sport", measurementsSection: "Mensurations (optionnel)", saved: "Pesée enregistrée", }, measurements: { title: "Mensurations", waist: "Tour de taille", hips: "Hanches", chest: "Poitrine", neck: "Cou", arm: "Bras", thigh: "Cuisse", calf: "Mollet", bodyFat: "Masse grasse estimée", empty: "Aucune mensuration enregistrée.", }, empty: { title: "Aucune pesée pour l'instant", hint: "Ajoutez votre première pesée ou importez un historique — la tendance et les projections apparaîtront dès 3 pesées.", }, bmiCategories: { underweight: "Maigreur", normal: "Corpulence normale", overweight: "Surpoids", obese: "Obésité", }, notConverging: "rythme insuffisant", }, /* ---------------------------------------------------------------- */ /* Nutrition */ /* ---------------------------------------------------------------- */ nutrition: { title: "Nutrition", kpi: { today: "Aujourd'hui", avg7: "Moyenne 7 j", protein: "Protéines aujourd'hui", split: "Répartition du jour", daysInBudget: "Jours dans le budget", avgGap: "Écart moyen au budget", }, charts: { kcalPerDay: "Calories par jour", macrosPerDay: "Macronutriments par jour", todaySplit: "Répartition du jour", perMeal: "Répartition par repas", topFoods: "Top aliments", }, series: { intake: "Apports", budget: "Budget", protein: "Protéines", carbs: "Glucides", fat: "Lipides", kcal: "Calories", }, journal: { title: "Journal du jour", totals: "Total", remaining: "Reste", addToMeal: "+ Ajouter un aliment", quantity: "Quantité", duplicate: "Dupliquer", filteredOn: "Filtré sur", clearFilter: "Retirer le filtre", }, meals: { breakfast: "Petit-déjeuner", lunch: "Déjeuner", dinner: "Dîner", snack: "Collations", }, modal: { title: "Ajouter un aliment", editTitle: "Modifier l'aliment", search: "Rechercher un aliment", searchPlaceholder: "ex. pain complet", favorites: "Favoris", recents: "Récents", catalog: "Catalogue", noResult: "Aucun aliment trouvé — saisissez les valeurs manuellement.", name: "Nom", meal: "Repas", quantity: "Quantité", unit: "Unité", kcal: "Calories (kcal)", protein: "Protéines (g)", carbs: "Glucides (g)", fat: "Lipides (g)", remember: "Mémoriser cet aliment dans ma bibliothèque", saved: "Aliment ajouté", }, empty: { title: "Rien dans le journal aujourd'hui", hint: "Ajoutez votre premier aliment ou importez votre historique Foodvisor depuis la page Imports.", }, }, /* ---------------------------------------------------------------- */ /* Activité & Sport */ /* ---------------------------------------------------------------- */ activity: { title: "Activité & Sport", kpi: { stepsToday: "Pas aujourd'hui", stepsAvg: "Moyenne pas (7 j)", activeKcalToday: "Kcal actives aujourd'hui", distance: "Distance (période)", sessionsWeek: "Séances cette semaine", goalReached: "Objectif atteint", adherence: "Assiduité 30 j", }, charts: { steps: "Pas par jour", activeKcal: "Calories actives par jour", weekly: "Entraînement par semaine", distance: "Distance cumulée", adherence: "Calendrier des séances", }, series: { steps: "Pas", movingAvg: "Moyenne 7 j", activeKcal: "Calories actives", distance: "Distance cumulée", }, records: { title: "Records", maxSteps: "Max pas en un jour", longestWorkout: "Plus longue séance", bestDistance: "Meilleure distance en séance", bestWeek: "Meilleure semaine", }, table: { title: "Séances", type: "Type", duration: "Durée", distance: "Distance", kcal: "Kcal", avgHr: "FC moy.", allTypes: "Tous les types", allSources: "Toutes les sources", }, modal: { title: "Ajouter une séance", editTitle: "Modifier la séance", type: "Type", date: "Date", startTime: "Heure de début", duration: "Durée (hh:mm)", distance: "Distance (km)", kcal: "Calories (kcal)", kcalPlaceholder: "estimées automatiquement si vide", avgHr: "FC moyenne (bpm)", saved: "Séance enregistrée", }, provenance: "Provenance des données du jour", stepsGoal: "Objectif de pas", empty: { title: "Aucune activité enregistrée", hint: "Connectez l'application compagnon Health Connect, importez un export FitShow, ou saisissez une séance manuellement.", }, }, /* ---------------------------------------------------------------- */ /* Balance énergétique */ /* ---------------------------------------------------------------- */ energy: { title: "Balance énergétique", kpi: { today: "Balance aujourd'hui", avgDeficit: "Déficit moyen (7 j)", cumulative: "Cumul (période)", tdee: "TDEE estimé", budget: "Budget quotidien", realVsModel: "Réel vs théorique", }, charts: { inOut: "Entrées vs sorties", net: "Balance nette quotidienne", cumulative: "Déficit cumulé", weightModel: "Poids théorique vs poids réel", }, series: { intake: "Apports", expenditure: "Dépense énergétique", net: "Balance nette", cumulative: "Déficit cumulé", realWeight: "Poids réel (tendance)", theoreticalWeight: "Poids théorique", targetDeficit: "Cible", }, /** Sous-titre du KPI « TDEE estimé » — comment la dépense a été obtenue (§5.2). */ tdeeMode: { measured_total: "Dépense totale mesurée", bmr_plus_active: (bmr: string) => `BMR ${bmr} + calories actives mesurées`, estimated: (bmr: string, factor: string) => `BMR ${bmr} × ${factor}`, }, method: { title: "Méthode & calibration", text: "Le métabolisme de base (BMR) est calculé avec la formule Mifflin-St Jeor à partir du poids de tendance du jour. La dépense totale (TDEE) applique ensuite votre facteur d'activité, ou ajoute vos calories actives mesurées. Les conversions énergie ↔ masse utilisent 7 700 kcal par kilogramme.", workoutsNote: "Les séances de sport ne sont pas ajoutées à la dépense du jour : seule l'activité quotidienne (pas, calories actives, dépense totale) alimente le TDEE. Une séance saisie sans donnée d'activité correspondante reste donc invisible dans cette balance.", calibration: "Calibration", insufficient: "Pas encore assez de jours suivis pour calibrer le modèle (21 jours minimum).", }, incomplete: "Données incomplètes", incompleteHint: (days: number) => `${days} jour${days > 1 ? "s" : ""} sans journal alimentaire sur la période. Les cumuls excluent ces jours.`, noLog: "journal incomplet", deficit: "déficit", surplus: "surplus", empty: { title: "Il manque des données", hint: "La balance énergétique a besoin de vos pesées et de votre journal alimentaire. Complétez ces deux modules pour débloquer cette page.", }, }, /* ---------------------------------------------------------------- */ /* Planning (addendum-planning.md) */ /* ---------------------------------------------------------------- */ planning: { title: "Planning", scheduleTitle: (habit: string) => `Planning — ${habit}`, scheduleHint: "Choisis les jours où tu prévois cette habitude.", enabled: "Planning activé", weekdays: ["L", "M", "M", "J", "V", "S", "D"], weekdaysAbbr: ["lun.", "mar.", "mer.", "jeu.", "ven.", "sam.", "dim."], weekdaysFull: ["lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche"], saved: "Planning enregistré", emptyPlan: "Aucun jour planifié. Choisis tes jours de pesée pour suivre ton assiduité.", emptyPlanWorkout: "Aucun jour planifié. Choisis tes jours de séance pour suivre ton assiduité.", nothingToday: "Rien de prévu aujourd'hui. Profites-en bien !", todayCard: { weighIn: "Pesée du jour", workout: "Séance du jour", }, status: { done: "Faite", planned: "Planifiée", missed: "Manquée", rest: "Repos", notPlanned: "Non planifiée", }, streak: (days: number) => `${days} jour${days > 1 ? "s" : ""} d'affilée`, bestStreak: "Record", adherence: "Assiduité", streakLabel: "Série en cours", legend: { done: "Faite", missed: "Planifiée manquée", planned: "Planifiée", off: "Non planifiée", }, habits: { weigh_in: "Pesée", workout: "Séance de sport", food_log: "Journal alimentaire", }, }, /* ---------------------------------------------------------------- */ /* Enum labels */ /* ---------------------------------------------------------------- */ sportTypes: { treadmill_walk: "Marche sur tapis", treadmill_run: "Course sur tapis", walking: "Marche", running: "Course à pied", cycling: "Vélo", swimming: "Natation", strength: "Renforcement", hiit: "Fractionné (HIIT)", yoga: "Yoga", hiking: "Randonnée", other: "Autre", }, sources: { manual: "Manuel", health_connect: "Health Connect", fitshow: "FitShow", foodvisor: "Foodvisor", csv_import: "Import CSV", api: "API", }, units: { g: "g", ml: "ml", portion: "portion", piece: "pièce", }, } as const; export type MealKey = keyof typeof S.nutrition.meals; const UNIT_LABELS: Record = { ...S.units }; const SOURCE_LABELS: Record = { ...S.sources }; const SPORT_LABELS: Record = { ...S.sportTypes }; /** French label of a quantity unit (falls back to the raw value). */ export function unitLabel(unit: string): string { return UNIT_LABELS[unit] ?? unit; } /** French label of a data source badge. */ export function sourceLabel(source: string): string { return SOURCE_LABELS[source] ?? source; } /** French label of a sport type. */ export function sportLabel(sportType: string, custom?: string | null): string { if (sportType === "other" && custom) return custom; return SPORT_LABELS[sportType] ?? sportType; }