Configuring translations
O3 supports multiple types of translations, each serving different purposes. This guide explains how to configure translations for your implementation.
Types of Translations
There are several categories of translations in O3:
Code Translations
We use Transifex to automatically extract hard-coded strings from the codebase (e.g., “Click Here”), translate them in the Transifex UI, and contribute those translations back to the O3 RefApp.
When to use: For translating the entire application into a new language or updating existing translations that will benefit the entire community.
How to contribute: Use Transifex to add or update translations for the O3 RefApp. See the “Contributing Translations” section below for more details.
Note: Code translations are different from translation overrides. Code translations are contributed through Transifex and become part of the application for all users. Translation overrides (covered below) are configuration-specific and only apply to your implementation.
Terminology Translations
Clinical terminology (concepts) can have translations attached to them. For example, the CIEL concept 121375 for Asthma has multiple translations (view here ).
When to use: When you need translations for clinical concepts (diagnoses, medications, etc.).
How to add: Add translations as metadata on the concept in Open Concept Lab (OCL) or via the Initializer module.
Form Translations
If you have translations attached to concepts you’re using in forms, those translations will automatically appear in your forms. Simply don’t supply a label in the Form Builder, and the form will use the concept name instead.
Note: The Form Builder may show an unlabeled question while editing if it has not resolved the concept metadata yet. At runtime, the React Form Engine uses the resolved concept display as the fallback label, and the Angular form-entry app uses the form schema’s conceptReferences map for the same kind of fallback.
New locales: If you add a brand-new locale not previously in O3, note that the form-entry-app expects translation files (e.g., ar.json) to exist. You may see issues with forms loading. See Issue O3-2492 for a workaround.
Translation Overrides
You can use the configuration system to override translations for specific O3 components. This is useful for:
- Changing button labels
- Renaming links or menu items
- Customizing text for your implementation
Important: Translation overrides should not be used to translate components into a new locale. For full translations, please contribute to the RefApp using Transifex .
Translation overrides are available at two configuration levels:
- Module-level (applies to all uses of the module)
- Extension-level (applies to a specific extension in a specific slot)
Module-Level Overrides
Override translations for an entire module by configuring the module that owns the translation namespace:
{
"@openmrs/esm-patient-vitals-app": {
"Translation overrides": {
"en": {
"Vitals & Biometrics": "Vitals and measurements"
},
"fr": {
"Vitals & Biometrics": "Signes vitaux et mesures"
}
}
}
}Extension-Level Overrides
Override translations for a specific extension in a specific slot. These overrides take precedence over module-level overrides for that extension.
Important: Extension configuration is specified under the module that owns the slot, not the extension’s module. The translation keys still come from the extension module’s translation namespace. For example, the patient chart module owns patient-chart-dashboard-slot, while results-summary-dashboard is provided by the vitals module.
{
"@openmrs/esm-patient-chart-app": {
"extensionSlots": {
"patient-chart-dashboard-slot": {
"configure": {
"results-summary-dashboard": {
"Translation overrides": {
"en": {
"Vitals & Biometrics": "Vitals"
}
}
}
}
}
}
}
}How Translation Overrides Work
-
Merging and precedence: Translation overrides are merged in this order (later overrides take precedence):
- Base translations from the module’s translation files
- Module-level overrides
- Extension-level overrides
If the same translation key is overridden at multiple levels, the extension-level override will be used for that specific extension instance.
-
Language codes: Language codes must follow the format:
[a-z]{2,3}(-[A-Z]{2,3})?- Valid examples:
en,fr,en-US,fr-CA,swa - Invalid examples:
EN,en_us,english
- Valid examples:
-
Translation keys: The translation key (e.g.,
startVisit) must match the key the component reads at runtime.- In most cases, that means a key from the module’s translation files. Adding a new key that no component reads has no visible effect.
- Translation keys are case-sensitive
- See the “Finding Translation Keys” section below for help locating the correct keys
-
Case sensitivity: The string
"Translation overrides"must be written exactly as shown (capital T, lowercase r, etc.).
Finding Translation Keys
To find the correct translation keys to override:
-
Inspect the code: Look in the module’s repository for translation files. Current O3 modules typically keep JSON files in a package-level
translations/directory, such astranslations/en.json. The module name usually matches the package name (e.g.,@openmrs/esm-patient-chart-app). -
Browser DevTools: Use the browser console to inspect i18n namespaces. The base namespace is the full module package name. Extension-scoped overrides use a derived namespace in the form
moduleName___slotName___extensionId, but most key lookup starts with the base module namespace:// Get all translations for a module window.i18next.getResourceBundle('en', '@openmrs/esm-patient-chart-app') // Or list all available namespaces window.i18next.store.data -
Module documentation: Some modules document their translation keys in their README or documentation files.
-
Implementer Tools: If the module is loaded, the configuration UI can confirm that “Translation overrides” is available for that module. It does not enumerate every translation key, so use the source files or i18next resources above for key lookup.
Complete Example
Here’s a complete example showing both override levels:
{
"@openmrs/esm-patient-vitals-app": {
"Translation overrides": {
"en": {
"Vitals & Biometrics": "Vitals and measurements"
}
}
},
"@openmrs/esm-patient-chart-app": {
"extensionSlots": {
"patient-chart-dashboard-slot": {
"configure": {
"results-summary-dashboard": {
"Translation overrides": {
"en": {
"Vitals & Biometrics": "Vitals"
}
}
}
}
}
}
}
}This configuration demonstrates:
- Module-level:
Vitals & Biometricsis overridden for the entire vitals module. - Extension-level:
Vitals & Biometricsis overridden only for theresults-summary-dashboardextension when it is rendered inpatient-chart-dashboard-slot. In that slot, the extension-level value takes precedence over the vitals module-level value.
Note: O3 does not currently support one slot-wide Translation overrides block that automatically applies to every extension in a slot. Configure each extension ID that needs slot-specific wording.
Troubleshooting
Translation override not working?
- Verify the translation key matches a key the component reads at runtime
- Check that
"Translation overrides"is spelled exactly as shown (case-sensitive) - Ensure the language code follows the correct format (e.g.,
en, notENoren-USnoten_us) - Verify the module is loaded (see the Overview guide for details on module loading)
- For extension-level overrides, ensure you’re configuring under the module that owns the slot, not the extension’s module
Can’t find translation keys?
- Use browser DevTools to inspect loaded translations (see “Finding Translation Keys” above)
- Check the module’s GitHub repository for translation files
- Some modules may use translation keys from other modules (check the module’s dependencies)
Contributing Translations
If you want to contribute translations to the O3 RefApp (rather than just overriding them for your implementation), you can help the community by adding translations through Transifex.
Getting started:
- Visit om.rs/translate for the complete translation guide
- Join the OpenMRS translation team on Transifex
- Select your language and start translating strings
Community support:
- OpenMRS Talk: Post questions in the translation category
- Slack: Join the
#translationchannel on OpenMRS Slack - Documentation: See the Guide to Using Transifex in OpenMRS for detailed instructions
Note: Contributing translations through Transifex helps the entire OpenMRS community. If you need translations for a new language or want to improve existing translations, please consider contributing rather than only using overrides for your implementation.
Related Documentation
- The Configuration System - Learn about the configuration system, including how “Translation overrides” is a reserved key in every module’s schema
- Extension System - Learn about configuring extensions and extension slots