D59. One package in every approved language, which learners switch in place (20 Oct 2026)
A translated course has been a package per language (SPEC §13, elabora translate build: a translated copy of the course, built and delivered on its own). Clients who train in several countries asked for one module in their LMS that each learner reads in their language; the founder decided the player’s « Langue » item on Lin 44 (20 October 2026) and asked the core how the package should hold the languages. Weighed:
- A package per language (as today): one LMS record per language, reports split by language, and a learner who changes language starts again. It stays for clients who want it.
- A course per language inside one SCORM package (several SCOs): SCORM 1.2 LMSs show each SCO as a separate activity and many track only the first; the learner’s progress is per SCO.
- One course in several languages, chosen at launch (a page before the module): one more screen, and the choice cannot be changed without starting again.
- One course whose texts and voices come in each language, switched in place. Chosen.
Decided:
- The package.
elabora build --languages all(MCPelabora_buildlanguages: "all",@elabora/nodebuild({ languages: 'all' })) holds the course’s own language and every translation that is ready (its texts complete, no stale or problematic unit, its word anchors placed) and whose translated plan is approved: the same rule as a translation’s own package, so that a package of every language holds nothing a reviewer has not approved. For SCORM 1.2 and the web alike. The course data of the course’s language stayselabora/course.js; each other language iselabora/course.<lang>.js, loaded only when a learner chooses it; the narration of each language is its own tracks,narration/<lang>/<screen>.m4aand their captions. Media are shared: a picture or a video is the same in every language (localised media are the case for a package per language). A screen whose lines are not all said in a language is said by the build (W_NARRATION_AUDIO_MISSING, with the language): learners who choose it get that screen’s timeline silent, on estimated times, as in the course’s own language. The element keys are the same in every language (the lock is the course’s), which is what lets a learner switch without losing anything. - The player. The item
language(« Langue ») shows when it is enabled and the package holds more than one language (else its reason,one language in the package). It is a chip with the language’s name in its own language (« Français », « English », fromIntl.DisplayNames) and a menu of the package’s languages; choosing one keeps the learner where they are: the state is synced to the LMS, the bars and the screen are rebuilt in the other language, and the learner is on the same screen with the same progress, answers, steps and variables (the course’s state is the same object, its keys unchanged); the focus comes back to the language button and the change is said in the live region. A module starts in the language the learner chose last time, else the course’s own: the course’s language is the client’s choice, and a browser’s language says little about the learner in a company’s LMS. - What is kept, and where. The language chosen is the last field of the learner’s state,
"g"(state codec,suspend_datain SCORM 1.2,localStorageon the web): a code of 2 to 16 letters, digits and hyphens, anything else ignored. It costs the length of,"g":"pt-BR"at most: the worst case the build checks against the LMS profiles’ limit (D9) adds the longest code of the package. Measured on 20 October 2026 with the orbital sample (English, with its approved French translation): the SCORM package goes from 409,308 to 418,958 bytes (+2.4 %:course.fr.js, 35 KB, 9.5 KB compressed), the suspend data worst case from 295 to 304 characters of 4,096. Narration is the heavy part: about 8 KB per second of narration and language at the package’s quality (the diagnostic sample’s two narrated screens, 318 KB). - What the LMS records does not depend on the language.
cmi.core.lesson_locationis the screen’s key, interactions are the block’s id with the answer’s letter (a,b…, the options keep their order in every language) or the learner’s number, objectives and scores are the course’s: a learner’s record reads the same whatever the language, and reports are not split.cmi.student_preference.languageis neither read nor written: SCORM 1.2 makes it optional for LMSs, few fill it, and the course’s state already says it. - Published on the web (added on 20 Oct 2026).
publishCourse({ languages: 'all' })andelabora publish --languages allpublish the package of every language; the publication’s languages are the package’s (the build report’slanguages, the course’s own first, absent with one). A review keeps one language per build (D42: the review page’s language menu loads a build per language, and the bridge anchors comments in the language it was built in), so a private publication refuses the option (E_CLOUD_PRIVATE_LANGUAGES). On the web, a translation’s course data has an id of its own (<id>-<lang>): what the browser keeps for the learner, their progress (elabora:web:<id>) and their display and narration choices, goes under the course’s own id, so that a learner who switches language keeps all of it, and after a reload too. The address stays the publication’s: the other languages’ files are beside the page, read relatively. - For authors and agents. The item is off in a new module, like « Affichage »;
elabora_playerlists the languages a package of every language would hold (content.languages), and the item says why it does not show when there is one.
Revisit if: clients need localised media in one package (then media per language beside the narration tracks), an LMS reports per language (then cmi.student_preference.language written as well), learners in a company ask to start in their browser’s language, or a package of many languages grows past an LMS’s upload limit (then each language’s narration downloaded on demand from the web target).