TL;DR — Multi-language SCORM is solvable but has more sharp edges than the spec suggests. Default to one package per locale, manage translations through a TMS-driven build pipeline, and validate against the actual target LMS — not just SCORM Cloud.
Why this is harder than web i18n
Web localization is dynamic — the browser fetches the right language at runtime. SCORM is static — a package is the unit of delivery, and most LMS-es expect a fixed structure. RTL languages, font fallbacks, character-set encoding, completion thresholds expressed in localized units — all add complexity that pure web teams rarely see.
Packaging strategies
- Package per locale — one ZIP per language. Cleanest LMS support, biggest storage footprint, simplest manifests. Default choice.
- Single package, language switcher — one ZIP, content selects language at runtime. Better author experience, but LMS completion tracking gets confused when learners switch mid-course.
- Per-AU language in cmi5 — multiple Assignable Units in one package, each in a different language. cmi5 supports it but support across authoring tools and LMS-es varies.
The translation workflow
- Source content in one canonical language (we use English)
- Strings extracted to a translation management system (Crowdin / Lokalise / Phrase)
- Translations imported back to a content build pipeline
- Builds run per locale, producing one SCORM package each
- Translation memory + glossary maintained per client to keep terminology consistent
Manifest considerations
- Title and description in
imsmanifest.xmlshould be in the target language - Course metadata language tag (
xml:lang) must match the package content - For SCORM 2004,
sequencingCollectionand rule labels do not need translation but should be reviewed - Avoid baking language hints into asset URLs — keep paths language-agnostic and let the build choose which assets are bundled
Common gotchas
- RTL layouts not tested. Arabic and Hebrew flip more than just text direction — UI affordances, icon placement and animations need separate review.
- Font fallback breaks. Embedded fonts work for Latin scripts but blow up on Cyrillic, Chinese or Devanagari. Plan font subsets per locale.
- Decimal and thousand separators. “1.000,50” (German) vs “1,000.50” (English) — quiz answers that compare strings will fail. Compare normalized numeric values.
- LMS interface language vs content language. A learner whose LMS is in English may still need Turkish content. Surface the content language separately.
- Encoding. Always UTF-8, BOM optional but consistent. UTF-16 SCORMs exist in the wild and cause subtle bugs.
Testing the package
- SCORM Cloud as a neutral baseline
- The actual target LMS — version-specific, because LMS interpretations drift
- RTL locale on a real device, not just a CSS toggle
- Long string overflow — German and Russian translations routinely run 30% longer than English; layouts need slack
Frequently asked questions
Should I ship one SCORM package per language?
For most LMS deployments, yes — one package per locale, each with its own manifest. Single-package multi-language exists but LMS support is uneven and the operational complexity rarely pays off.
How do I keep translations in sync with the source?
Use a translation management system (Crowdin, Lokalise, Phrase) and a content build pipeline that fails when source strings have moved without their translations updating. Treat translations as a build artifact, not a manual export.
Working on something similar?
T-Square is an independent software engineering studio. We architect, build and operate production-grade systems for learning, AI and custom software products. Talk to a senior engineer if you’d like a second opinion on your architecture or roadmap.
