Overview
Kolibri is designed for worldwide use and has strong internationalization (i18n) support. All user-visible text must be translatable.Frontend Internationalization
Using createTranslator
All frontend strings usecreateTranslator from kolibri/utils/i18n:
The
$ suffix convention indicates these are translation functions. Call them as functions: pageTitle$()Message Definition Format
Each message has two parts:pageTitle, errorMessage)
Message: The English text that will be translated
Context: Critical for translators to understand usage. Include:
- Where the text appears (page heading, button label, error message)
- How it’s used
- Any special meaning
ICU Message Syntax
Kolibri uses ICU message syntax for dynamic content:Variables
Plurals
zero: Used in some languages for zeroone: Singulartwo: Used in some languages for exactly twofew: Used in some languages for small numbersmany: Used in some languages for larger numbersother: All other cases (required)=N: Exact match for specific number
Select (Conditionals)
Number Formatting
Common Strings Modules
To avoid duplicating the same string across multiple files, use common strings modules:commonStrings.js
Only add strings to common modules if used in three or more files to avoid bloat.
Backend Internationalization
Backend code uses Django’s standard i18n tools:Right-to-Left (RTL) Support
Kolibri fully supports right-to-left languages like Arabic, Hebrew, and Urdu.Automatic CSS Flipping
RTLCSS automatically flips directional CSS properties:Text Direction
Application text (using$tr or createTranslator):
- Automatically aligned based on current language direction
- No special handling needed
- Must have
dir="auto"on parent element - Browser detects text direction automatically
RTL Behavior
For direction-dependent logic, use theisRtl property:
Icon Flipping
UseKIcon from the Design System - it handles RTL flipping automatically:
Material Design guideline: “Anything that relates to time should be depicted as moving from right to left [in RTL].” For example, forward points left in RTL.
Crowdin Workflow
Kolibri uses Crowdin for translations.For Developers
Extracting and Uploading Strings
At the beginning of string freeze (before a release):Pre-translation
After uploading, pre-translate strings using translation memory:Downloading Translations
Periodically during development, download latest translations:- Rebuilds the Crowdin project
- Downloads all translations
- Compiles Django messages
- Regenerates fonts and CSS
- Regenerates Intl JS files
For Translators
- Visit Kolibri on Crowdin
- Select your language
- Browse files and translate strings
- Use the context field to understand how strings are used
- Translations are automatically included in the next release
Adding a New Language
To add a new supported language to Kolibri:Find Language Codes
crowdin_code: Crowdin language codesintl_code: Intl.js language codes (lowercase)language_name: Native language nameenglish_name: English language namedefault_font: Noto font for the language
Add to EXTRA_LANG_INFO (if needed)
If Django doesn’t recognize the language, add to
EXTRA_LANG_INFO in kolibri/deployment/default/settings/base.pyTest the Language
Start Kolibri and switch to the new language. Verify:
- Strings are translated
- Fonts render correctly (should use Noto)
- RTL works (if applicable)
- Perseus exercises work
Best Practices
Never hard-code user-visible text
Never hard-code user-visible text
All strings must use
createTranslator (frontend) or gettext (backend).Provide context for every string
Provide context for every string
Translators need context to translate accurately. Always include meaningful context.
Use descriptive message IDs
Use descriptive message IDs
IDs should describe the content:
pageTitle, errorMessage, not msg1, text2.Use ICU syntax for plurals and variables
Use ICU syntax for plurals and variables
Don’t construct strings with concatenation. Use ICU plural/select syntax.
Don't split sentences
Don't split sentences
Keep complete sentences together. Don’t split into parts for reuse.
Use common strings sparingly
Use common strings sparingly
Only add to common modules if used in 3+ files.
Always use dir=auto for user content
Always use dir=auto for user content
User-generated text needs
dir="auto" for proper RTL/LTR display.Use style blocks for directional styles
Use style blocks for directional styles
RTLCSS can’t flip inline styles. Put directional CSS in
<style> blocks.Test RTL thoroughly
Test RTL thoroughly
Test your UI in an RTL language (Arabic, Hebrew) to catch direction issues.
Common Patterns
Loading States
Error Messages
Confirmation Messages
Date/Time Formatting
Use Intl APIs for dates and times - they handle localization automatically:Testing Translations
Test your UI with different languages:Testing RTL
Test with RTL languages:- Arabic (ar)
- Hebrew (he)
- Urdu (ur)
Resources
- ICU Message Syntax
- Crowdin ICU Documentation
- Material Design Bidirectionality
- Unicode Bidirectional Algorithm
- Django i18n Documentation
Next Steps
Frontend Development
Learn how to use createTranslator in Vue components
Backend Development
Use Django’s gettext for backend strings
Testing
Test your internationalized code
Design System
KIcon handles RTL flipping automatically