# How to customize i18n (translation)

**URL:** <https://discuss.openedx.org/t/how-to-customize-i18n-translation/17356>\
**Category:** Development\
**Tags:** how-to, i18n, tutor, translation, customization\
**Created:** [October 10, 2025, 10:17pm UTC](https://discuss.openedx.org/t/how-to-customize-i18n-translation/17356 "2025-10-10T22:17:35Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![pauldic](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/pauldic/32/8631_2.png) [@pauldic](https://discuss.openedx.org/u/pauldic)\
**Post date:** [October 10, 2025, 10:17pm UTC](https://discuss.openedx.org/t/how-to-customize-i18n-translation/17356/1 "2025-10-10T22:17:35Z")

</div>

I did fork the [openedx-translations repository](https://github.com/openedx/openedx-translations) according to the [tutor documentation](https://docs.tutor.edly.io/configuration.html#getting-and-customizing-translations), created a branch “teak.2-custom” on my forked repository and made my desired changes on the existing English verbiage, commit and pushed to my branch “teak.2-custom”.

> **[Configuration and customisation — Tutor documentation](https://docs.tutor.edly.io/configuration.html#getting-and-customizing-translations)**

Update the atlas revision and repository in the tutor config:

tutor config save \  
–set ATLAS\_REVISION=“teak.2-custom” \  
–set ATLAS\_REPOSITORY=“MyUsername/openedx-translations”

Run these commands without error:  
tutor images build mfe  
tutor images build openedx  
tutor local launch

I can confirm during the build for both the mfe & openedx, that it actual pulled from MyUsername/openedx-translations. However, the UI does not reflect my changes.

> Please guys can you help me confirm if there is something am doing wrong?
> 
> Below if part of the log during mfe build
> 
> [+] Building 41.2s (108/149) docker:default  
> =\> [authn-common 6/7] RUN make OPENEDX\_ATLAS\_PULL=true ATLAS\_OPTIONS=“–repository=MyUsername/openedx-translations --revision=teak.2-custom " pull\_translations 19.4s  
> [+] Building 41.4s (108/149) docker:default  
> =\> [authn-common 6/7] RUN make OPENEDX\_ATLAS\_PULL=true ATLAS\_OPTIONS=”–repository=MyUsername/openedx-translations --revision=teak.2-custom " pull\_translations 19.6s  
> [+] Building 650.3s (128/149) docker:default  
> [+] Building 1738.0s (150/150) FINISHED
> 
> Below is part of the log during openedx build:
> 
> =\> CACHED [production 18/37] RUN make clean\_translations 0.0s  
> =\> [production 19/37] RUN ./manage.py lms --settings=tutor.i18n pull\_plugin\_translations --verbose --repository=‘MyUsername/openedx-translations’ --revision=‘teak.2-custom’ 41.8s  
> =\> [production 20/37] RUN ./manage.py lms --settings=tutor.i18n pull\_xblock\_translations --repository=‘MyUsername/openedx-translations’ --revision=‘teak.2-custom’ 25.3s  
> =\> [production 21/37] RUN atlas pull --repository=‘MyUsername/openedx-translations’ --revision=‘teak.2-custom’ translations/edx-platform/conf/locale:conf/locale translations/studio-frontend/src 24.8s  
> =\> [production 22/37] RUN ./manage.py lms --settings=tutor.i18n compile\_xblock\_translations 31.0s  
> =\> [production 23/37] RUN ./manage.py cms --settings=tutor.i18n compile\_xblock\_translations 27.0s  
> =\> [production 24/37] RUN ./manage.py lms --settings=tutor.i18n compile\_plugin\_translations 17.7s  
> =\> [production 25/37] RUN ./manage.py lms --settings=tutor.i18n compilemessages -v1 22.2s  
> =\> [production 26/37] RUN ./manage.py lms --settings=tutor.i18n compilejsi18n 26.5s  
> =\> [production 27/37] RUN ./manage.py cms --settings=tutor.i18n compilejsi18n 16.7s

---

<div class="post-metadata">

**Author:** ![sarina](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/sarina/32/2308_2.png) [@sarina](https://discuss.openedx.org/u/sarina)\
**Post date:** [October 14, 2025, 9:18pm UTC](https://discuss.openedx.org/t/how-to-customize-i18n-translation/17356/2 "2025-10-14T21:18:22Z")

</div>

@omar or @brian.smith any ideas?

---

<div class="post-metadata">

**Author:** ![brian.smith](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/brian.smith/32/4259_2.png) [@brian.smith](https://discuss.openedx.org/u/brian.smith)\
**Post date:** [October 14, 2025, 10:05pm UTC](https://discuss.openedx.org/t/how-to-customize-i18n-translation/17356/3 "2025-10-14T22:05:42Z")

</div>

Hopefully I can help here!

To clarify: did you use “MyUsername” in `MyUsername/openedx-translations` or your GitHub username (the one you forked `openedx-translations` to)?

Also you mentioned changing the English, what file(s) did you change?

---

<div class="post-metadata">

**Author:** ![pauldic](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/pauldic/32/8631_2.png) [@pauldic](https://discuss.openedx.org/u/pauldic)\
**Post date:** [October 15, 2025, 3:40am UTC](https://discuss.openedx.org/t/how-to-customize-i18n-translation/17356/4 "2025-10-15T03:40:30Z")

</div>

I mean my actual username (My-Github-Username).  
The actual files that I updated are:

- translations/edx-platform/conf/locale/en/LC\_MESSAGES/djangojs.po
- translations/frontend-app-authn/src/i18n/messages/de.json
- translations/frontend-app-authn/src/i18n/messages/de.json
- translations/frontend-app-authn/src/i18n/messages/id.json
- translations/frontend-app-authn/src/i18n/transifex\_input.json
- translations/frontend-app-learner-dashboard/src/i18n/transifex\_input.json

I noticed the text I need to update are contained in these files, hence the changes (though I am interested in the English version only atleast for now)

---

<div class="post-metadata">

**Author:** ![brian.smith](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/brian.smith/32/4259_2.png) [@brian.smith](https://discuss.openedx.org/u/brian.smith)\
**Post date:** [October 15, 2025, 1:49pm UTC](https://discuss.openedx.org/t/how-to-customize-i18n-translation/17356/5 "2025-10-15T13:49:28Z")

</div>

> [@pauldic](#):
>
> I am interested in the English version only atleast for now

That is definitely what is making this more complicated.

> [@pauldic](#):
>
> - translations/frontend-app-authn/src/i18n/transifex\_input.json
> - translations/frontend-app-learner-dashboard/src/i18n/transifex\_input.json

Modifying `transifex_input.json` doesn’t change anything for MFEs. Since English is the default/fallback language, changing the English strings for MFEs requires modifying source files in the MFEs themselves.

Supporting this use case for MFEs would require architectural changes.

> **Detailed explanation/example**
>
> As the name suggests for these files, they are used as _input_ for Transifex. They are just a compilation of the English source strings that exist within each MFE.
> 
> Using `logistration.sign.in` in `frontend-app-authn` as an example:
> 
> The source string exists in [`src/common-components/messages.jsx`](https://github.com/openedx/frontend-app-authn/blob/ffb8a2d434b201fd97c64d3b35215e4ffaf1d595/src/common-components/messages.jsx#L11-L15):
> 
> ```jsx
> 'logistration.sign.in': {
> id: 'logistration.sign.in',
> defaultMessage: 'Sign in',
> description: 'Text that appears on the tab to switch between login and register',
> },
> 
> ```
> 
> And extracted/concatenated into `transifex_input.json` when [`make extract_translations`](https://github.com/openedx/frontend-app-authn/blob/ffb8a2d434b201fd97c64d3b35215e4ffaf1d595/Makefile#L16-L25) is run.
> 
> When [`make pull_translations`](https://github.com/openedx/frontend-app-authn/blob/ffb8a2d434b201fd97c64d3b35215e4ffaf1d595/Makefile#L32-L41) is run, the `src/i18n/messages` directory is populated
> 
> ```bash
> ├── i18n
> │ ├── index.js
> │ └── messages
> │ ├── frontend-app-authn
> │ │ ├── af_ZA.json
> │ │ ├── ar.json
> │ │ ├── az.json
> │ │ ├── da.json
> │ │ ├── de.json
> │ │ ├── de_DE.json
> │ │ ├── el.json
> │ │ ├── es_419.json
> │ │ ├── es_ES.json
> │ │ ├── fa.json
> │ │ ├── fr_CA.json
> │ │ ├── he.json
> │ │ ├── hi.json
> │ │ ├── hu.json
> │ │ ├── id.json
> │ │ ├── index.js
> │ │ ├── it_IT.json
> │ │ ├── ja.json
> │ │ ├── lv.json
> │ │ ├── pt_BR.json
> │ │ ├── pt_PT.json
> │ │ ├── ro.json
> │ │ ├── ru.json
> │ │ ├── sv.json
> │ │ ├── sw.json
> │ │ ├── te.json
> │ │ ├── th.json
> │ │ ├── tr_TR.json
> │ │ ├── uk.json
> │ │ ├── uz.json
> │ │ ├── vi.json
> │ │ ├── zh_CN.json
> │ │ └── zh_HK.json
> │ ├── frontend-platform
> │ │ ├── ar.json
> │ │ ├── az.json
> │ │ ├── bo.json
> │ │ ├── da.json
> │ │ ├── de_DE.json
> │ │ ├── el.json
> │ │ ├── es_419.json
> │ │ ├── es_ES.json
> │ │ ├── fa.json
> │ │ ├── fr_CA.json
> │ │ ├── he.json
> │ │ ├── hi.json
> │ │ ├── hu.json
> │ │ ├── id.json
> │ │ ├── index.js
> │ │ ├── it_IT.json
> │ │ ├── ja.json
> │ │ ├── lv.json
> │ │ ├── pt_BR.json
> │ │ ├── pt_PT.json
> │ │ ├── ro.json
> │ │ ├── ru.json
> │ │ ├── te.json
> │ │ ├── th.json
> │ │ ├── tr_TR.json
> │ │ ├── uk.json
> │ │ ├── uz.json
> │ │ ├── vi.json
> │ │ ├── zh_CN.json
> │ │ └── zh_HK.json
> │ └── paragon
> │ ├── af_ZA.json
> │ ├── ar.json
> │ ├── az.json
> │ ├── da.json
> │ ├── de.json
> │ ├── de_DE.json
> │ ├── el.json
> │ ├── es_419.json
> │ ├── es_ES.json
> │ ├── fa.json
> │ ├── fr_CA.json
> │ ├── he.json
> │ ├── hi.json
> │ ├── hu.json
> │ ├── id.json
> │ ├── index.js
> │ ├── it_IT.json
> │ ├── ja.json
> │ ├── lv.json
> │ ├── pt_BR.json
> │ ├── pt_PT.json
> │ ├── ru.json
> │ ├── sv.json
> │ ├── sw.json
> │ ├── te.json
> │ ├── th.json
> │ ├── tr_TR.json
> │ ├── uk.json
> │ ├── uz.json
> │ ├── vi.json
> │ ├── zh_CN.json
> │ └── zh_HK.json
> 
> ```
> 
> but there is no `en.json`, and no `transifex_input.json`. The English strings are coming from the default messages.
> 
> Adding `en.json` also doesn’t work (see [`frontend-platform`’s `src/i18n/lib.js`](https://github.com/openedx/frontend-platform/blob/77d409a626fbef4e3fdf44bcb62649cb61d6b36b/src/i18n/lib.js#L40-L58))
> 
> ```js
> const supportedLocales = [
> 'ar', // Arabic
> // NOTE: 'en' is not included in this list intentionally, since it's the fallback.
> 'es-419', // Spanish, Latin American
> 'fa', // Farsi
> 'fa-ir', // Farsi, Iran
> 'fr', // French
> 'zh-cn', // Chinese, Simplified
> 'ca', // Catalan
> 'he', // Hebrew
> 'id', // Indonesian
> 'ko-kr', // Korean (Korea)
> 'pl', // Polish
> 'pt-br', // Portuguese (Brazil)
> 'ru', // Russian
> 'th', // Thai
> 'uk', // Ukrainian
> 'vi', // Vietnamese
> ];
> 
> ```
> 
> So the only way to change English strings in MFEs at the moment is to modify the `defaultMessage`s in the MFEs themselves.

> [@pauldic](#):
>
> - translations/edx-platform/conf/locale/en/LC\_MESSAGES/djangojs.po

I’d need to verify with @omar on this one. I’d _think_ that modifying `en/LC_MESSAGES/djangojs.po` would lead to changes to the English strings in there, but I haven’t verified.

---

<div class="post-metadata">

**Author:** ![pauldic](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/pauldic/32/8631_2.png) [@pauldic](https://discuss.openedx.org/u/pauldic)\
**Post date:** [October 16, 2025, 9:17am UTC](https://discuss.openedx.org/t/how-to-customize-i18n-translation/17356/6 "2025-10-16T09:17:57Z")

</div>

@brian.smith Thank you so much for your clarification and detailed explaination on this. So just as you suggested I had to clone the individual MFEs and make the changes needed directly in the source. Based on my understanding on what is going on [here](https://github.com/overhangio/tutor-mfe/blob/release/tutormfe/plugin.py), I have now made a custom plugin to override the default MFEs of interest and so far, it is looking good (I am not sure if this is the best way to override MFEs though)

from tutormfe.hooks import MFE\_APPS  
@MFE\_APPS.add()  
def \_override\_authn\_mfe(apps):  
apps[“authn”] = {  
“repository”: “[https://github.com/MyUsername/frontend-app-authn.git”](https://github.com/MyUsername/frontend-app-authn.git%E2%80%9D),  
“port”: 1999,  
“version”: “teak.201”  
}  
apps[“learner-dashboard”] = {  
“repository”: “[https://github.com/MyUsername/frontend-app-learner-dashboard.git”](https://github.com/MyUsername/frontend-app-learner-dashboard.git%E2%80%9D),  
“port”: 1996,  
“version”: “teak.202”  
}

---

<div class="post-metadata">

**Author:** ![omar](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/omar/32/7275_2.png) [@omar](https://discuss.openedx.org/u/omar)\
**Post date:** [October 29, 2025, 12:03pm UTC](https://discuss.openedx.org/t/how-to-customize-i18n-translation/17356/7 "2025-10-29T12:03:06Z")

</div>

> [@brian.smith](#):
>
> I’d need to verify with @omar on this one. I’d _think_ that modifying `en/LC_MESSAGES/djangojs.po` would lead to changes to the English strings in there, but I haven’t verified.

That’s what I haven’t tried. But feel free to do so @pauldic
