Skip to Content
DocsConfigure O3Configure translations

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

  1. 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.

  2. 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
  3. 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
  4. 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:

  1. 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 as translations/en.json. The module name usually matches the package name (e.g., @openmrs/esm-patient-chart-app).

  2. 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
  3. Module documentation: Some modules document their translation keys in their README or documentation files.

  4. 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 & Biometrics is overridden for the entire vitals module.
  • Extension-level: Vitals & Biometrics is overridden only for the results-summary-dashboard extension when it is rendered in patient-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, not EN or en-US not en_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:

  1. Visit om.rs/translate  for the complete translation guide
  2. Join the OpenMRS translation team on Transifex 
  3. Select your language and start translating strings

Community support:

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.

  • 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
Last updated on