Last Updated: March 29, 2018
· paprikkastudio

Localized templates with Handlebars / Mustache

Currently I'm using AngularJS + JADE combo in almost all of my projects but before that time I had a lot of fun with Backbone / Backbone Marionette.

Some time ago one of our customers decided to localize whole web app which already contained a quite large front end codebase, client-side templating and Backbone / Marionette, Handlebars, require.js under the hood.

At the same time, we were launching new version of the app and didn't want to refactor almost everything, in other words - we wanted to minimize the impact of another new feature, yet still - we wanted to keep things clean, simple and easy to maintain.

That's the solution I came up with. Hope you'll find it helpful.


I decided to use i18n plugin for require.js

Translator class

I've created a CoffeeScript class which returns a compile() method for currently selected language version:

# file: modules/localized-template.coffee
define (require)->
  _                  = require 'lodash'
  Handlebars  = require 'handlebars'

  LocalizedTemplate = (dict, tpl) ->
      dictModel = 
        i18n : dict
      params = _.extend {}, model, dictModel
      rendered = Handlebars.compile tpl
      rendered params

Thanks to _.extend method we are able to preserve all strings / view model data created in the view controller and override only necessary strings.


# file: modules/view-name/view-controller-name.coffee
define (require)->
  require 'jquery'
  require 'backbone'
  require 'Backbone.Marionette'
  Handlebars      = require 'handlebars'

  VideoView       = require './video'
  StreamTemplate  = require 'text!./tpl/stream.tpl'

  # most important part:    
  LocalizedTemplate       = require 'cs!modules/localized-template'

  i18n = 
    ui : require 'i18n!nls/ui' 

  StreamView = VideoView.extend
    # here we swap Handlebars.compile method:
    template : LocalizedTemplate i18n, StreamTemplate
    tagName : 'li'


That's quite simple: we place localized strings under i18n.ui.variableName.

# file: modules/view-name/tpl/stream.tpl
<div class="icon">
  <img width="240" height="135" src="{{#if posterUrl}}{{{posterUrl}}}{{else}}/img/video-list/not-found.png{{/if}}" alt="{{title}}">
    <div class="labels">
      <span class="language">{{language.label}}</span>
      <div class="specializations">
        {{#each specializations}}
        <span class="specialization">{{name}}</span>
<div class="description">
  <div class="title">{{title}}</div>
  <div class="author">{{author}}</div>
  <div class="affiliation">{{affiliation}}</div>
  <div class="labels">
    <span class="date">{{parsedStartTime}}</span>
    <button class="subscribe">{{i18n.ui.subscribe}}</button>    

It's important not to pollute "global" template scope. What if there was a localized variable called specializations = "Specialisierung"? In this case it would be overwritten by array pulled from JSON. That's just evil.

Localized strings

I've implemented it according to official documentation.