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"
      theme_setting_name: "This is a description for the setting `theme_setting_name`"
        description: "This is a description for the setting `another_theme_setting_name`"
    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 .hbs files, 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:

<DButton @label={{theme-prefix "my_translation_key"}} />

In Javascript, or in .gjs files, you can use the themePrefix function. This is automatically injected, and does not need to be imported:

const result = I18n.t(themePrefix("my_translation_key"))

  {{i18n (themePrefix "blah")}}

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

Last edited by @david 2024-07-01T13:32:18Z

Check documentPerform check on document:

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 @Don

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 @Don ,

The reason I used that facebook example is because of:

Thanks again !

What about singular and plural, how to translate text using {{theme-i18n}} if it has one and many translations. For instance “Result” and “Results”


There are some examples of how we do this in Discourse’s source, typically we have two strings and switch based on an integer:

Screenshot 2022-12-15 at 5.42.58 PM

This should work in a theme too, generally the JS would look something like:

I18n.t(themePrefix("confirm_remove_tags"), {
  count: exampleCountValue,
1 Like

and what about hbs, can it be done in hbs templates?

1 Like

Yes it can:

{{theme-i18n "confirm_remove_tags" count=this.exampleCountValue}}

when I do that in a .gjs Component template within a Theme I get:

Error: Attempted to resolve a helper in a strict mode template, but that value was not in scope: theme-prefix

So I attempt to import it:

import themePrefix from "discourse/helpers/theme-prefix";

But it grumbles:

Identifier 'themePrefix' has already been declared

(I looked for an example in on the 'hub but there doesn’t seem to be one)

1 Like

Update: you need to use {{i18n (themePrefix "