Skill: Internationalization (i18n)
SkillDev toolsAdding translatable strings or modifying translations with _() / c_() helpers. Every change must run `make translations` to sync keys, keep existing unit/integration/E2E suites green, maintain patch coverage ≥ 90% on any touched code, and pass `make fix`, `make test-unit`, `make test-integration`, and `make test-e2e` before submission.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Skill: Internationalization (i18n) skill
What this skill tells your AI
The instructions your AI receives, as published by exelearning/exelearning in .agents/skills/i18n/SKILL.md and read by ahel’s review.
Parent: AGENTS.md | Related: frontend-module
When to Use
Adding translatable strings, modifying translations, or working with localized content.
Key Files
translations/messages.*.xlf— translation files (en, es, ca, va, eu, gl, pt, eo, ro, etc.)src/services/translation.ts— server-side translation servicepublic/app/locate/— client-side localization helpersviews/*.njk— Nunjucks templates (use| transfilter)
Documentation: doc/development/internationalization.md
Patterns
JavaScript (public/app/):
button.title = `${_('Undo')} (Ctrl+Z)`; // GUI string — translated per user's locale
const label = c_('Learning objectives'); // Content string — translated per content locale
Nunjucks (views/):
<button>{{ 'Save' | trans }}</button>
_() vs c_() — When to Use Which
| Function | Context | Example |
|---|---|---|
_() | GUI strings (menus, tooltips, buttons) | _('Save'), _('Undo') |
c_() | Content strings (exported with the project) | c_('Learning objectives') |
The distinction matters because the GUI language and the content language can differ (e.g., Spanish teacher creating English-language content).
Commands
make fix # Lint (the only command this skill ever runs)
make translationsandmake translations-cleanupare never run by agents. Key extraction and all XLF changes are managed by a dedicated separate process. See the prohibition below.
Gotchas
- NEVER touch any file under
translations/. This is a hard rule. Do not runmake translations, do not add or remove<trans-unit>elements, do not write or edit<target>values. A PR that modifiestranslations/**in any way will be rejected. Translation key extraction is handled by a separate automated process outside of code PRs. - Never hardcode English strings in UI code — even "OK" or "Cancel" must use
_(). _()vsc_()confusion — using the wrong function means the string is translated in the wrong context. GUI strings →_(), content strings →c_().- Forgetting
| transin Nunjucks — raw English strings will appear in the UI for non-English users. - Static build config drift — if translated strings appear in config parameters, ensure both server and static builder use the same shared function. Duplicated config leads to untranslated strings in one of the two builds. Example: PR #1564.
Done When
- All user-facing strings use
_()/c_()/| trans - No file under
translations/has been modified -
make translationshas NOT been run - No hardcoded English in UI
-
make fixpasses clean
Signals
- GitHub stars
- 142
- Forks
- 32
- Last commit
- Sep 2026
- Hacker News mentions
- 4
Advanced
- Catalog kind
- skill
- Gateway key
i18n-exelearning- Source
- github.com/exelearning/exelearning