refactor(i18n): split fitness translations into per-locale files
The fitness UI translation table previously lived as one combined
object in fitnessI18n.ts where every entry held both languages. That
hides drift (an English string can silently disappear without TypeScript
noticing) and makes adding strings a multi-edit dance.
Split into src/lib/i18n/fitness/{de,en}.ts. de.ts is the source of
truth for the key set; en.ts uses `as const satisfies
Record<keyof typeof de, string>` so any missing English translation is
a build-time error. fitnessI18n.ts now re-exports both as a typed
table m and adds FitnessLang/FitnessKey types — the existing
t/fitnessSlugs/fitnessLabels API stays so call sites don't churn.
The strict typing immediately surfaced one real bug: t('initializing_gps')
was being called from the active workout page but the key never existed
in the dictionary, so it had been rendering the literal string
'initializing_gps' through the fallback. Added the missing key in both
locales.
Tightened BodyPartCard.labelKey and the body-parts Step JSDoc to
FitnessKey instead of plain string so card data drift catches drift at
the data site, not the call site. Two dynamic-key sites (partKeyMap
fallbacks for unmapped measurement keys) are cast pragmatically.
The 360-entry split was done by a one-shot extraction script
(scripts/split-fitness-i18n.ts) — kept for re-use against
cospendI18n.ts and calendarI18n.ts in follow-up commits.
This commit is contained in:
@@ -0,0 +1,366 @@
|
||||
/** Generated by scripts/split-fitness-i18n.ts. */
|
||||
import type { de } from './de';
|
||||
|
||||
export const en = {
|
||||
save: "Save",
|
||||
saving: "Saving…",
|
||||
cancel: "CANCEL",
|
||||
delete_: "Delete",
|
||||
edit: "Edit",
|
||||
loading: "Loading…",
|
||||
set: "set",
|
||||
sets: "sets",
|
||||
exercise: "exercise",
|
||||
exercises_word: "exercises",
|
||||
kg: "kg",
|
||||
km: "km",
|
||||
min: "min",
|
||||
stats_title: "Stats",
|
||||
workout_singular: "Workout",
|
||||
workouts_plural: "Workouts",
|
||||
lifted: "Lifted",
|
||||
est_kcal: "Est. kcal",
|
||||
burned: "Burned",
|
||||
kcal_set_profile: "Set sex & height in",
|
||||
covered: "Covered",
|
||||
workouts_per_week: "Workouts per week",
|
||||
sex: "Sex",
|
||||
male: "Male",
|
||||
female: "Female",
|
||||
height: "Height (cm)",
|
||||
birth_year: "Birth Year",
|
||||
no_workout_data: "No workout data to display yet.",
|
||||
weight: "Weight",
|
||||
history_title: "History",
|
||||
no_workouts_yet: "No workouts yet. Start your first workout!",
|
||||
load_more: "Load more",
|
||||
date: "Date",
|
||||
time: "Time",
|
||||
duration_min: "Duration (min)",
|
||||
notes: "Notes",
|
||||
notes_placeholder: "Workout notes...",
|
||||
gps_track_stored: "GPS track stored",
|
||||
add_set: "+ ADD SET",
|
||||
add_exercise: "+ ADD EXERCISE",
|
||||
splits: "Splits",
|
||||
pace: "PACE",
|
||||
upload_gpx: "Upload GPX",
|
||||
uploading: "Uploading...",
|
||||
download_gpx: "Download GPX",
|
||||
elevation: "Elevation",
|
||||
elevation_unit: "m",
|
||||
elevation_gain: "Gain",
|
||||
elevation_loss: "Loss",
|
||||
cadence: "Cadence",
|
||||
cadence_unit: "spm",
|
||||
cadence_permission_missing: "Cadence disabled — grant Activity Recognition in system settings",
|
||||
personal_records: "Personal Records",
|
||||
delete_session_confirm: "Delete this workout session?",
|
||||
remove_gps_confirm: "Remove GPS track from this exercise?",
|
||||
recalc_title: "Recalculate volume, PRs, and GPS previews",
|
||||
next_in_schedule: "Next in schedule",
|
||||
start_empty_workout: "Empty Workout",
|
||||
templates: "Templates",
|
||||
schedule: "Schedule",
|
||||
my_templates: "My Templates",
|
||||
no_templates_yet: "No templates yet. Browse the library or create your own.",
|
||||
template_library: "Template Library",
|
||||
browse_library: "Browse Library",
|
||||
template_added: "Template added",
|
||||
edit_template: "Edit Template",
|
||||
new_template: "New Template",
|
||||
template_name_placeholder: "Template name",
|
||||
add_set_lower: "+ Add set",
|
||||
add_exercise_btn: "Add Exercise",
|
||||
save_template: "Save Template",
|
||||
workout_schedule: "Workout Schedule",
|
||||
schedule_hint: "Select templates and arrange their order. After completing a workout, the next one in the rotation will be suggested.",
|
||||
available_templates: "Available templates",
|
||||
all_templates_scheduled: "All templates are in the schedule",
|
||||
save_schedule: "Save Schedule",
|
||||
start_workout: "Start Workout",
|
||||
delete_template: "Delete",
|
||||
workout_complete: "Workout Complete",
|
||||
workout_saved_offline: "Saved offline — will sync when back online.",
|
||||
duration: "Duration",
|
||||
tonnage: "Tonnage",
|
||||
distance: "Distance",
|
||||
exercises_heading: "Exercises",
|
||||
volume: "volume",
|
||||
avg: "avg",
|
||||
update_template: "Update Template",
|
||||
template_updated: "Template updated",
|
||||
template_diff_desc: "Your weights or reps differ from the template:",
|
||||
updating: "Updating...",
|
||||
view_workout: "VIEW WORKOUT",
|
||||
done: "DONE",
|
||||
workout_name_placeholder: "Workout name",
|
||||
cancel_workout: "CANCEL WORKOUT",
|
||||
finish: "FINISH",
|
||||
new_set_added: "new set",
|
||||
new_sets_added: "new sets",
|
||||
exercises_title: "Exercises",
|
||||
search_exercises: "Search exercises…",
|
||||
no_exercises_match: "No exercises match your search.",
|
||||
type_any: "Any type",
|
||||
type_weights: "Strength",
|
||||
type_stretches: "Stretches",
|
||||
stretch_pill: "Stretch",
|
||||
strength_pill: "Strength",
|
||||
cardio_pill: "Cardio",
|
||||
plyo_pill: "Plyo",
|
||||
about: "ABOUT",
|
||||
history_tab: "HISTORY",
|
||||
charts: "CHARTS",
|
||||
records: "RECORDS",
|
||||
instructions: "Instructions",
|
||||
no_history_yet: "No history for this exercise yet.",
|
||||
est_1rm: "EST. 1RM",
|
||||
best_set_1rm: "Best Set (Est. 1RM)",
|
||||
best_set_max: "Best Set (Max Weight)",
|
||||
total_volume: "Total Volume",
|
||||
not_enough_data: "Not enough data to display charts yet.",
|
||||
estimated_1rm: "Estimated 1RM",
|
||||
max_volume: "Max Volume",
|
||||
max_weight: "Max Weight",
|
||||
rep_records: "Rep Records",
|
||||
reps: "REPS",
|
||||
best_performance: "BEST PERFORMANCE",
|
||||
measure_title: "Measure",
|
||||
profile: "Profile",
|
||||
profile_setup_cta: "Add height & birth year to unlock BMI, TDEE and calorie balance stats.",
|
||||
set_up_profile: "Set up",
|
||||
edit_profile: "Edit profile",
|
||||
dismiss: "Dismiss",
|
||||
new_measurement: "New Measurement",
|
||||
edit_measurement: "Edit Measurement",
|
||||
weight_kg: "Weight (kg)",
|
||||
body_fat: "Body Fat %",
|
||||
calories_kcal: "Calories (kcal)",
|
||||
body_parts_cm: "Body Parts (cm)",
|
||||
neck: "Neck",
|
||||
shoulders: "Shoulders",
|
||||
chest: "Chest",
|
||||
l_bicep: "L Bicep",
|
||||
r_bicep: "R Bicep",
|
||||
l_forearm: "L Forearm",
|
||||
r_forearm: "R Forearm",
|
||||
waist: "Waist",
|
||||
hips: "Hips",
|
||||
l_thigh: "L Thigh",
|
||||
r_thigh: "R Thigh",
|
||||
l_calf: "L Calf",
|
||||
r_calf: "R Calf",
|
||||
biceps: "Biceps",
|
||||
forearms: "Forearms",
|
||||
thighs: "Thighs",
|
||||
calves: "Calves",
|
||||
measure_tip_neck: "Just below the Adam’s apple, tape parallel to the floor.",
|
||||
measure_tip_shoulders: "Widest point across the deltoids, arms relaxed at your sides.",
|
||||
measure_tip_chest: "At nipple line after a normal exhale, tape horizontal.",
|
||||
measure_tip_biceps: "Arm flexed at the peak; tape around the thickest part.",
|
||||
measure_tip_forearms: "Widest point below the elbow, arm hanging relaxed.",
|
||||
measure_tip_waist: "At the navel, relaxed — don’t suck in.",
|
||||
measure_tip_hips: "Around the widest point of the buttocks.",
|
||||
measure_tip_thighs: "Midway between hip crease and knee.",
|
||||
measure_tip_calves: "Widest point, standing with weight on both feet.",
|
||||
save_measurement: "Save Measurement",
|
||||
update_measurement: "Update Measurement",
|
||||
measure_body_parts: "Measure body parts",
|
||||
measure_body_parts_sub: "Guided tape-measure flow — one part at a time.",
|
||||
last_measured: "Last measured",
|
||||
no_measurements_yet: "No measurements yet",
|
||||
step_n_of_m: "Step {n} of {m}",
|
||||
over_time: "{label} over time",
|
||||
first_measurement_hint: "First measurement — your entry will appear here.",
|
||||
running_totals: "Running totals",
|
||||
review_save: "Review & save",
|
||||
ready_to_save: "Ready to save",
|
||||
review_numbers: "Review your numbers below.",
|
||||
skip: "Skip",
|
||||
next: "Next",
|
||||
back: "Back",
|
||||
review: "Review",
|
||||
edit_again: "Edit again",
|
||||
exit: "Exit",
|
||||
same_both_sides: "Same on both sides",
|
||||
copy_l_to_r: "Copy L → R",
|
||||
copy_l_to_r_before: "Copy L",
|
||||
copy_l_to_r_after: "R",
|
||||
kbd_nav: "nav",
|
||||
kbd_next: "next",
|
||||
kbd_skip: "skip",
|
||||
kbd_wheel: "±0.1",
|
||||
kbd_hint: "Press ? for shortcuts",
|
||||
no_body_parts_selected: "Enter at least one value before saving.",
|
||||
today_short: "today",
|
||||
latest: "Latest",
|
||||
body_fat_short: "Body Fat",
|
||||
calories: "Calories",
|
||||
body_parts: "Body Parts",
|
||||
body_measurements_only: "Body measurements only",
|
||||
delete_measurement_confirm: "Delete this measurement?",
|
||||
general: "General",
|
||||
body_fat_pct: "Body Fat (%)",
|
||||
history: "History",
|
||||
past_measurements: "Past measurements",
|
||||
show_more: "Show more",
|
||||
overwrite_title: "Overwrite existing values?",
|
||||
overwrite_message: "You already have values for this date: {fields}. Replace them?",
|
||||
overwrite_confirm: "Overwrite",
|
||||
same_as_last: "Same as last",
|
||||
set_header: "SET",
|
||||
prev_header: "PREV",
|
||||
rpe: "RPE",
|
||||
picker_title: "Add Exercise",
|
||||
no_exercises_found: "No exercises found",
|
||||
last_performed: "Last performed:",
|
||||
today: "Today",
|
||||
yesterday: "Yesterday",
|
||||
days_ago: "days ago",
|
||||
more: "more",
|
||||
active_workout: "Active Workout",
|
||||
streak: "Streak",
|
||||
streak_weeks: "Weeks",
|
||||
streak_week: "Week",
|
||||
weekly_goal: "Weekly Goal",
|
||||
workouts_per_week_goal: "workouts / week",
|
||||
set_goal: "Set Goal",
|
||||
goal_set: "Goal set",
|
||||
intervals: "Intervals",
|
||||
no_intervals: "None",
|
||||
new_interval: "New Interval",
|
||||
edit_interval: "Edit Interval",
|
||||
delete_interval: "Delete",
|
||||
delete_interval_confirm: "Delete this interval template?",
|
||||
add_step: "+ Add Step",
|
||||
add_group: "+ Add Repeat Group",
|
||||
repeat_times: "times",
|
||||
ungroup: "Ungroup",
|
||||
group_label: "Repeat",
|
||||
step_label: "Label",
|
||||
meters: "meters",
|
||||
seconds: "seconds",
|
||||
intervals_complete: "Intervals complete",
|
||||
select_interval: "Select Interval",
|
||||
custom: "Custom",
|
||||
steps_count: "steps",
|
||||
save_interval: "Save Interval",
|
||||
interval_name_placeholder: "Interval name",
|
||||
label_easy: "Easy",
|
||||
label_moderate: "Moderate",
|
||||
label_hard: "Hard",
|
||||
label_sprint: "Sprint",
|
||||
label_recovery: "Recovery",
|
||||
label_hill_sprints: "Hill Sprints",
|
||||
label_tempo: "Tempo",
|
||||
label_warm_up: "Warm Up",
|
||||
label_cool_down: "Cool Down",
|
||||
nutrition_title: "Nutrition",
|
||||
breakfast: "Breakfast",
|
||||
lunch: "Lunch",
|
||||
dinner: "Dinner",
|
||||
snack: "Snack",
|
||||
add_food: "Add food",
|
||||
search_food: "Search food…",
|
||||
amount_grams: "Amount (g)",
|
||||
meal_type: "Meal",
|
||||
daily_goal: "Daily Goal",
|
||||
calorie_target: "Calorie target (kcal)",
|
||||
protein_goal: "Protein goal",
|
||||
protein_fixed: "Fixed (g/day)",
|
||||
protein_per_kg: "Per kg bodyweight",
|
||||
fat_percent: "Fat ratio",
|
||||
carb_percent: "Carbs ratio",
|
||||
kcal: "kcal",
|
||||
protein: "Protein",
|
||||
fat: "Fat",
|
||||
carbs: "Carbs",
|
||||
remaining: "left",
|
||||
over: "over",
|
||||
no_entries_yet: "No entries yet. Add food to start tracking.",
|
||||
set_goal_prompt: "Set a daily calorie goal to start tracking.",
|
||||
micro_details: "Micronutrients",
|
||||
of_daily: "of daily goal",
|
||||
per_serving: "per serving",
|
||||
log_food: "Log",
|
||||
delete_entry_confirm: "Delete this food entry?",
|
||||
period_tracker: "Period Tracker",
|
||||
current_period: "Current Period",
|
||||
no_period_data: "No period data yet. Log your first period to start tracking.",
|
||||
no_active_period: "No active period.",
|
||||
start_period: "Start Period",
|
||||
end_period: "Period Ended",
|
||||
period_day: "Day",
|
||||
predicted_end: "Predicted end",
|
||||
next_period: "Next period",
|
||||
cycle_length: "Cycle length",
|
||||
period_length: "Period length",
|
||||
avg_cycle: "Avg. cycle",
|
||||
avg_period: "Avg. period",
|
||||
days: "days",
|
||||
delete_period_confirm: "Delete this period entry?",
|
||||
add_past_period: "Add Past Period",
|
||||
period_start: "Start",
|
||||
period_end: "End",
|
||||
ongoing: "ongoing",
|
||||
share: "Share",
|
||||
shared_with: "Shared with",
|
||||
add_user: "Add user…",
|
||||
no_shared: "Not shared with anyone.",
|
||||
shared_by: "Shared by",
|
||||
fertile_window: "Fertile window",
|
||||
peak_fertility: "Peak fertility",
|
||||
ovulation: "Ovulation",
|
||||
fertile: "Fertile",
|
||||
luteal_phase: "Luteal",
|
||||
predicted_ovulation: "Predicted ovulation",
|
||||
to: "to",
|
||||
overview: "Overview",
|
||||
tips: "Tips",
|
||||
similar_exercises: "Similar Exercises",
|
||||
primary_muscles: "Primary",
|
||||
secondary_muscles: "Secondary",
|
||||
play_video: "Play Video",
|
||||
nutrition_stats: "Nutrition",
|
||||
protein_per_kg_unit: "g/kg",
|
||||
calorie_balance: "Calorie Balance",
|
||||
calorie_balance_unit: "kcal/day",
|
||||
diet_adherence: "Adherence",
|
||||
seven_day_avg: "7-day avg",
|
||||
thirty_day: "30 days",
|
||||
macro_split: "Macro Split",
|
||||
no_nutrition_data: "No nutrition data yet. Start logging food to see stats.",
|
||||
target: "Target",
|
||||
days_tracked: "days tracked",
|
||||
since_start: "Since start",
|
||||
no_weight_data: "Log weight to enable",
|
||||
no_calorie_goal: "Set calorie goal",
|
||||
muscle_balance: "Muscle Balance",
|
||||
weekly_sets: "Sets per week",
|
||||
custom_meals: "Custom Meals",
|
||||
custom_meal: "Custom Meal",
|
||||
new_meal: "New Meal",
|
||||
meal_name: "Meal name",
|
||||
add_ingredient: "Add ingredient",
|
||||
no_custom_meals: "No custom meals yet.",
|
||||
create_meal_hint: "Create reusable meals for quick logging.",
|
||||
ingredients: "Ingredients",
|
||||
total: "Total",
|
||||
log_meal: "Log Meal",
|
||||
delete_meal_confirm: "Delete this custom meal?",
|
||||
save_meal: "Save Meal",
|
||||
favorites: "Favorites",
|
||||
per_100g: "per 100 g",
|
||||
macros: "Macronutrients",
|
||||
minerals: "Minerals",
|
||||
vitamins: "Vitamins",
|
||||
amino_acids: "Amino Acids",
|
||||
essential: "Essential",
|
||||
non_essential: "Non-Essential",
|
||||
saturated_fat: "Saturated Fat",
|
||||
fiber: "Fiber",
|
||||
sugars: "Sugars",
|
||||
source_db: "Source",
|
||||
initializing_gps: "Initializing GPS…",
|
||||
} as const satisfies Record<keyof typeof de, string>;
|
||||
Reference in New Issue
Block a user