Add localizable strings to themes and theme components

For those looking to add custom languages and translations to a Discourse theme or theme component, they can now include localised strings, which are made available for use in UI components. Translations are stored in the same format as core/plugin translations, and can be used in almost the same way.

Themes can supply translation files in a format like /locales/{locale}.yml. These files should be valid YAML, with a single top level key equal to the locale being defined. These can be defined using the discourse_theme CLI, importing a .tar.gz, installing from a GIT repository, or via the editor on

An example locale file might look like

    description: "This is a description for my theme"
    welcome: "Welcome"
    back: "back,"
    welcome_subhead: "We're glad you're here!"
    likes_header: "Share the Love"
    badges_header: "Your Top Badges"
    full_profile: "View your full profile"

Administrators can override individual keys on a per-theme basis in the /admin/customize/themes user interface. Fallback is handled in the same way as core, so it is ok to have incomplete translations for non-english languages will make use of the english keys.

In the background, these translations are stored alongside the core translations, under a theme-specific namespace. For example:


You should never hardcode the theme_id in your theme code, so there are a few ways to help you access the translations. In handlebars templates, you can use the dedicated helper

{{theme-i18n "my_translation_key"}}

Or, if you need to pass the translation key into another component, you can use the theme-prefix helper:

{{d-button label=(theme-prefix 'my_translation_key')}}

In Javascript, you can use the themePrefix function.


For a complete example of using translations in a theme, check out @awesomerobot’s Fakebook theme: GitHub - discourse/Fakebook


Howto use theme translations in CSS ? I know we can use theme parameters but I need theme translations.

You can’t, they’re only available in templates and javascript. That’s the same as core/plugin translations.

Ideally, refactor things so that the string is set in a template. But if you really need a customisable string in a css file, you could use theme settings: Developer’s guide to Discourse Themes

1 Like

And if I use theme setting, is it possible to translate it ?

No, not in to multiple languages, but it would allow admins to customize it for their site.


Hello everyone.
I’m redefining the template upload-selector.hbs
I want to add a translatable phrase.
I created a new variable upload_selector.upload_images
For example

Please tell me what to do next?


when i try this technic in the discourse theme creator (see here) everything works fine and as explained here in the post.

However if I import the very same theme on my own server only " []" appears. Also in the theme settings page there is no “Theme Translations” section like on the theme creator.

I really don’t know where to search for this error anymore. Has anybody a hint for me?

I’m using discourse 2.6.7 ( [f73cdbbd2f ] ) in an docker environment.

can you update discourse ?

you are using an old version

Yeah i’m trying that, that is another thing i need help with but, I don’t want to post it here, that’s another topic.

Anyway I thought that shouldn’t be problem as the translation feature was included in version 2.2.0.beta9, see commit.

Hello, sorry in advance for a newbs question here.
I created a header with just html and css

        <div class="top-navbar">
         <span class="j_menu_item" ><a href="">Download</a></span>     

And then I want to translate the word “Download”
I created the english translation file

    download: "Yeah"

Then I changed the html code as for the facebook example

    <script type="text/x-handlebars" data-template-name="/connectors/discovery-below/sidebar">
        <div class="top-navbar">
         <span class="j_menu_item" ><a href="">{{i18n (theme-prefix "")}}</a></span>     

This translates and prints “Yeah” but breaks my layout, I guess it is because I’m using the “/connectors/discovery-below/sidebar”. I just want to apply my translation without messing with any template but I don’t understand how to just apply the translation inline.

Could you please provide a simple example on how to just use a translation in the custom html of a theme ?

Thanks !


The problem is, the data-template-name should be unique name. Developer’s guide to Discourse Themes. Like this: data-template-name="/connectors/PLUGIN-OUTLET-NAME/UNIQUE-NAME" Now you use the sidebar name in your example which is I think override Fakebook sidebar template.

For example this should work :slightly_smiling_face:

<script type="text/x-handlebars" data-template-name="/connectors/discovery-below/downloadlink">
  <div class="top-navbar">
    <span class="j_menu_item" ><a href="">{{i18n (theme-prefix "")}}</a></span>     

Thanks @dodesz

I forgot to mention that plugin is not installed and that I tried already to change the data-template-name to something a random UNIQUE-NAME with the same result or not showing my banner at all if I made up the PLUGIN-OUTLET-NAME.

You can probably tell by now , I’m not familiar at all with handlebars/ember :slight_smile:

My understanding is that I’m customizing a template that has it’s predefined place in the html and has a result the custom html is not anymore over /html/body/section main but deep inside resulting in css inheritance I didn’t have before.

What I struggle to understand is Why do I need to customize any template to use a translation…
I managed to identify the template to customize using Ember inspector as advised here

And thanks to your answer and link about the plugin-outlet I found the right data-template-name=“/connectors/above-site-header/my-navbar”

Thanks again for your help

1 Like

Oh I see… I thought you using the Fakebook theme and want to place your code below the sidebar section. :slightly_smiling_face:

A good way to see the plugin outlets visually you can use the Plugin Outlet Locations theme component.


Hi @dodesz ,

The reason I used that facebook example is because of:

Thanks again !