Making Plugin Templates Localization friendly

If you are familiar with WordPress plugins, you may have noticed that the more popular ones take advantage of gettext so that their text can be translated.
It takes a little bit of effort to wrap text inside of functions instead of hard-coding it, but the effort is well worth it.

Fortunately, Discourse also provides a way for plugin text to be translatable.

For example, the Discourse Plugin Outlet Locations plugin currently has around 40 template files. All were similar to

{{#if siteSettings.mitt_plugin_outlet_locations_enabled}}
  {{#if siteSettings.mitt_show_header_after_home_logo_enabled}}
<div class="mitt-outlet-location">
  <i class="fa fa-plug"></i>
  header-after-home-logo plugin outlet
</div>
  {{/if}}
{{/if}}

Notice that the text string, “header-after-home-logo plugin outlet” is hard-coded into the template.

So if I, or anyone else, wanted to make changes, it would mean that around 40 lines of code in around 40 different files would need to be edited.
Even if tedium is not problem for you, the plugin author, it can get old fast, it is more likely errors will be made, and it just plain does not make it any easier for others to change or translate the text strings.

The first step is to put all of the text strings into the client.en.yml file.
There may still be around 40 lines of code, but making changes in one file is a lot easier than making changes in around 40 different files.
And if, for example, someone wanted a Spanish version, they could translate the text strings, change the yml file’s “en:” token to “es:”, rename the file client.es.yml, and be good to go.

For example, the above text is used by a unique token

en:
  js:
    mitt_dpol:
      header_after_home_logo_dpol: "header-after-home-logo plugin outlet"

and the template file is changed to

{{#if siteSettings.mitt_plugin_outlet_locations_enabled}}
  {{#if siteSettings.mitt_show_header_after_home_logo_enabled}}
<div class="mitt-outlet-location">
  <i class="fa fa-plug"></i>
  {{i18n "mitt_dpol.header_after_home_logo_dpol"}}
</div>
  {{/if}}
{{/if}}

Now, any changes made to the string in the yml file will be used by the template without needing to edit the template file directly.

OK, that works fine for simple text strings, but what if the string has HTML in it? eg.

en:
  js:
    plugin_outlet_locations:
      title: "Plugin Outlet Locations"
      show: "Show Purple Tentacle"
      hide: "Hide Purple Tentacle"
      first_para_dpol: "This page has nothing to do with this plugin for now.<br>Eventually I hope to move this plugin's settings here."
      second_para_dpol: "At present it's only here to provide a working example of <br><a href='https://meta.discourse.org/t/beginners-guide-to-creating-discourse-plugins-part-5-admin-interfaces/31761'>Beginner's Guide to Creating Discourse Plugins Part 5: Admin Interfaces</a>"

No problem, the template file only needs a couple more curly braces.

<div>
  <p>{{{i18n "plugin_outlet_locations.first_para_dpol"}}}</p>
  <p>{{{i18n "plugin_outlet_locations.second_para_dpol"}}}</p>
</div>

What HTML to have in the template file and what HTML to have in the yml file could be open to debate, my personal feeling is that keeping the yml file as “clean” of HTML as possible would be the better choice, but what you do is of course up to you.

May your plugin go global :smile:

9 Likes