Add French (fr) exercise instructions

Adds a tenth language to all 1,324 exercises: `instructions.fr` and
`instruction_steps.fr`, plus the schema, README, viewer and setup guide.

Register matches the existing Spanish/Italian/Polish translations —
informal second-person imperative (tutoiement):

  en: Lie flat on your back with your knees bent and feet flat on the ground.
  fr: Allonge-toi sur le dos, les genoux fléchis et les pieds à plat au sol.

How it was produced
-------------------
The 7,710 English step sentences deduplicate to 4,414 unique strings.
Those were translated (LLM-assisted, glossary-constrained, then audited),
and the per-exercise arrays were rebuilt deterministically by mapping each
English step back through that table. `instructions.fr` is the join of
`instruction_steps.fr`, so the two can never drift.

A fixed glossary pinned the recurring terms — répétitions, position de
départ, haltère/barre, sangle abdominale, omoplates, largeur des épaules —
so terminology is consistent across all 1,324 records rather than varying
sentence by sentence.

Verified
--------
- 1,324 records validate against the updated schema; a record missing `fr`
  is now rejected.
- fr step count == en step count in every record (the dataset's existing
  invariant across all nine prior languages).
- instructions.fr == ' '.join(instruction_steps.fr) in every record.
- Every pre-existing field is byte-identical; `fr` is purely additive.
- No empty strings, none left in English, no vouvoiement across 7,710 steps.
- index.html embed stays in sync with data/exercises.json; the language
  picker renders "Français" and the steps display correctly.

Note for review: these are machine translations, reviewed programmatically
rather than by a native speaker. Happy to adjust any wording.
This commit is contained in:
umutcakirai
2026-07-10 15:58:52 +03:00
parent daceea8667
commit 6f3031b3b2
5 changed files with 13029 additions and 1340 deletions
+6 -4
View File
@@ -20,9 +20,10 @@
"zh": { "type": "string" },
"hi": { "type": "string" },
"pl": { "type": "string" },
"ko": { "type": "string" }
"ko": { "type": "string" },
"fr": { "type": "string" }
},
"required": ["en", "es", "it", "tr", "ru", "zh", "hi", "pl", "ko"],
"required": ["en", "es", "it", "tr", "ru", "zh", "hi", "pl", "ko", "fr"],
"additionalProperties": { "type": "string" }
},
"languageStepsMap": {
@@ -37,9 +38,10 @@
"zh": { "$ref": "#/$defs/steps" },
"hi": { "$ref": "#/$defs/steps" },
"pl": { "$ref": "#/$defs/steps" },
"ko": { "$ref": "#/$defs/steps" }
"ko": { "$ref": "#/$defs/steps" },
"fr": { "$ref": "#/$defs/steps" }
},
"required": ["en", "es", "it", "tr", "ru", "zh", "hi", "pl", "ko"],
"required": ["en", "es", "it", "tr", "ru", "zh", "hi", "pl", "ko", "fr"],
"additionalProperties": { "$ref": "#/$defs/steps" }
},
"steps": {