Last Updated: September 27, 2021
·
16.27K
· 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.

Tools

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) ->
 (model)->
 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.

View

# 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'
 StreamView

Template

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>
 {{/each}}
 </div>
 </div>
</div>
<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> 
 </div>
</div>

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.