Using i18n + handlebars in an express app, but not to generate output html, how to localize? - node.js

I have an Express app in which I want to use handlebars to generate localised templated emails to be sent out. The problem is that handlebars requires a globally registered helper to translate items inside the .hbs files, while I need to use a construct such as app.use(i18n.init) to make sure my __ function translates according to the right locale in the context of the current request. Setting a locale globally will lead to concurrency issues.
The only 'solutions' (which aren't because they don't solve my problem) I found consist of using handlebars middleware to output html using Express, but that is not what I want to do. I want to generate content that's completely independent from what Express sends back to the client.
This is what I am currently doing, which obviously isn't the way to do it
const i18n = require("i18n")
const Handlebars = require('handlebars')
i18n.configure({
directory: './i18n',
defaultLocale: 'en',
objectNotation: true,
syncFiles: true
})
Handlebars.registerHelper('i18n',
function (str) {
if(!str) return str
return i18n.__(str)
}
)
to be used as
<td>
{{i18n "title"}}
</td>
A possible solution is to do the translations in code by calling i18n.__({phrase: "someText", locale: locale}) but I would like to keep this inside the template.
How can I make sure handlebars uses the i18n instance bound to the Express response object?

Related

Node js, express and handlebars - where to apply logic to data before rendering

I am new to node js, express and the handlebar template engine.
I have managed to get data from a json feed and it is rendering correctly in the view. I am doing this by getting the data in the app, then passing the data into and from the router to the view.
However, I need to manipulate and add some logic to some of the json data and the render it.
The feed i have is of an article, it has a publish date value which is in a particular format and i need to format it accordingly and then render it.
My question is, where do i apply the logic for data manipulation so when i render it via the handlebars template, it renders the required format.
The boiler plate folder structure i have setup is;
/server
...
/src
...
/views
...
In the view, i have the following in the home.hndlebars file.
<div class="publish">{{{ article.post.date }}}</div>
I need to format that value.
Thanks
you can make a helper in handlebars it's very helpful in many cases. for yours I would do something like this:
const exphbs = require('express-handlebars');
const moment = require('moment')
var hbs = exphbs.create({
defaultLayout: 'main.handlebars',
// Specify helpers which are only registered on this instance.
helpers: {
moment: function(date) {
return moment(date).format('DD-MM-YYYY');
}
}
})
and then in the html you use the helpers like this:
<div class="publish">{{#moment article.post.date}}{{/moment}}</div>

How to properly use dustjs & create helpers in sailsjs?

I'm using sailsjs to build my website but decided not to use its default EJS for templating.
In ./config/views.js, I have set the the following(after npm install dustjs-linkedin & dustjs-helpers):
engine: 'dust',
In my HomeController ./api/controllers/HomeController.js, I need to do the following to get the language text from ./config/locales/en.json:
title: res.i18n('title'),
//or
siteName: res.__('siteName')
In my home template ./views/home/index.dust, I can access those string with:
<h1>{title}</h1>
<p>{siteName}</p>
However, as the number of strings grow, it will be redundant as I have to set each of the variables in controller before I can use it in my template.
So my questions are:
is there a better or correct way to use the text variables in my template from ./config/locales/en.json without having to define each of them in my controller file?
how to access & use the dustjs module in my controller so that..
I can create custom dustjs helpers? (how to create dustjs helpers?)
also, it seems I cannot configure the settings for i18n in ./config/i18n.js (objectNotation: true not working) Is this the correct place to configure i18n?
Its a long ques. I'll answer the part: I can create custom dustjs helpers? (how to create dustjs helpers?)
Ans. Yes you can. Here's how (in sailsjs):
We can create a globally accessible service in api/services/MultiplyBy2.js
MultiplyBy2.js
module.exports = {
myFunc: function (chunk, context, bodies, params) {
var number = params.num;
number = number*2;
return chunk.write(number);
}
};
And then you can use this in a dustjs template like so:
<p>10 * 2 = {#sails.services.multiplyby2.myFunc num=10/}</p>
Note: The file name (MultiplyBy2) will be lowercase. But the function name will be the same as defined (myFunc);
Hope this helps.
I also had this problem. I further dug into this and figured that it's too much hassle to resolve this issue, and that's when I switched to Handlebars on Sails.js.
Handlebars' i18n's syntax in Sails.js is {{__ 'Welcome' }} .

Do I only have to use a templating language with express render?

I am learning node and express from the simplest and when rendering views using res.render('view',{data:data}) is it only a template engine like jade that fits in view. can I not use a normal html?
You can, but this is a problem I ran into when I was learning Node. If you do not want to use a templating engine, you can still have Node just spit out the contents of your HTML file in a static way. For example (VERY BASIC EXAMLE):
var base = '/path/to/your/public_html',
fs = require('fs'),
http = require('http'),
sys = requrie('sys');
http.createServer(function (req,res) {
path = base + req.url;
console.log(path);
path.exists(path, function(exists) {
if(!exists) {
res.writeHead(404);
res.write('Bad request: 404\n');
res.end();
} else {
res.setHeader('Content-Type','text/html');
res.statusCode = 200;
var file = fs.createReadStream(path);
file.on("open",function() {
file.pipe(res);
});
file.on("error",function(err) {
console.log(err);
});
}
});
}).listen(80);
console.log('server on tcp/80');
The great thing about Node is that it forces you to separate templates from logic (to a certain level, you can squeeze a lot of logic into template anyway).
I didn't like Jade and used EJS until it turned out that client-side EJS is different from server-side and you cannot really re-use templates in the browser (as you would definitely want at some point, when you start rendering pages in the browser). You can re-use simple EJS templates but you cannot re-use templates with partials (as most of your templates will be).
After a lot of searching and trial-and-error I ended up using doT templates that are very fast (the fastest there is, actually), light-weight (only 140 lines of JavaScript), can be easily integrated in Express (by following the pattern of consolidate - you can't use consolidate directly with doT yet), can be used in the browser (the function to load partials will have to be different, but it is easy again).
doT seems to have features that I haven't seen in other templating engines, has a very elegant syntax that is the closest to handlebars (my favourite) but still allows normal JavaScript inside (that's why I chose EJS in the first place).

Node.js + Express - How to get Mustache partials working?

I'm trying to get Mustache working properly with Express, and as one can guess, I'm having troubles.
The following line initializes Mustache nice and clean. Variables render as expected.
app.register('html', require(__dirname+'/public/js/libs/mustache.js'));
However, the problems start to rise when partials are thrown in the mix. With Mustache, this here partial should invoke header view/partial.
{{> header}}
But alas, nothing happens. :/ Even when I offer the partial directly, Mustache fails to render it.
app.get('/', function(req, res) {
res.render('welcome', {
partials: {
header: '<h1>Header</h1>'
}
});
});
So, it seems that the partials aren't working at all. I've found one hack that get's the partials somewhat working:
http://bitdrift.com/post/2376383378/using-mustache-templates-in-express
After that the partials render when offered directly at render call (see above), but it still fails on rendering the partials directly to views/layouts:
Layout looks something like this:
Behold, the header
{{> header}}
<p>Let's move to more important stuff...</p>
Header view looks something like this:
<h1>Header</h1>
Express can load the views by themselves just ok, but it doesn't know how to handle the Mustache partials...
Using express (at least version 3) and mustache-express, You can load partials as usual using double mustaches that begin with a greater than sign.
First consider the following is appended within our app.js file:
/** import the module */
import mustache from 'mustache-express';
/** view engine setup */
app.engine('mst', mustache());
app.set('view engine', 'mst');
app.set('views', path.join(__dirname, 'mvc/views'));
/** the route where we will display the partials */
app.get('/', (req, res) => {
let view = {
title: 'Homepage',
// ...
};
/** we are going to use a file called template.mst for rendering */
res.render('template', view);
});
Any double mustaches that begin with a greater than sign (i.e. {{> file}}) will be considered a partial. The file within the partial will be rendered at runtime. Consider this file to be a partial we want to insert:
mvc/views/partial.mst
<h2>418 | I'm a teapot</h2>
And here is our template:
mvc/views/template.mst
<h1>template.mst file</h1>
<!-- output: <h2>418 | I'm a teapot</h2> -->
{{> partial}}
Managed to get this working with the latest version of hogan-express.
https://github.com/vol4ok/hogan-express
All that is needed is to install hogan-express and use it as template engine on express. No hacking or tuning required.
I'm not sure what's exactly in your ./public/js/libs/mustache.js ... I use the mustache module from npm + a variation of the templating object you linked to.
In any case, the object you pass to app.register needs to call mustache.to_html(template, locals, partials) at some point.
You need to pass the partials object as the third argument to mustache's to_html.

Mustache(-like) template engine for Express?

Is there a template engine for Express (node.js) which is based on Mustache or uses a similar syntax?
All I could find is haml, jade, ejs, jquery templates and one based on CoffeeScript (I write plain JS).
I want to write "normal" html, so only ejs and jqtpl would fit. I already use mustache with backbone so it would be best to also use it on the server side with Node.js
Just stumbled on this ancient thread but no one has mentioned consolidate.js, which seems to be the "right" way under Express 3 (refer to http://expressjs.com/faq.html). It also provides an easy way to switch/experiment with templating systems.
Here's a simple example - http://invitingthebell.com/2012/12/24/mustache-templates-in-express-3-0/.
Code, in case it disappears is:
var express = require('express')
, cons = require('consolidate')
, app = express();
// assign the mustache engine to .html files
app.engine('html', cons.mustache);
// set .html as the default extension
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
// test mustache
app.get('/', function(req, res){
var viewdata = { 'test' : 'Hey now.'};
res.render('index', viewdata);
});
app.listen(3000);
The index.html file in the views directory:
<html>
<head><title>Some CMS</title></head>
<body>
<h1>Mustache</h1>
<p>What do you say?</p>
<p>{{test}}</p>
</body>
</html>
You could probably add Mustache as a rendering engine by following the Express manual:
View filenames take the form “.”, where is the name of the module >that will be required. For example the view layout.ejs will tell the view system to >require(‘ejs’), the module being loaded must export the method exports.compile(str, >options), and return a Function to comply with Express.
Edit:
From the Mustache manual under Usage:
Below is quick example how to use mustache.js:
var view = {
title: "Joe",
calc: function () {
return 2 + 4;
}
};
var output = Mustache.render("{{title}} spends {{calc}}", view);
In this example, the Mustache.render function takes two parameters: 1) the mustache >template and 2) a view object that contains the data and code needed to render the >template.
From the above I suspect you could just export Mustache.render, but I haven't tested it. The object literals used as data look the same, but if they do happen to be different, you could probably just wrap Mustache.render in a function that formats it correctly.
Edit: Xomby's wrapper link contains an example of how to wrap handlebars for express, Mustache should be similar.
Try Hogan.js http://twitter.github.com/hogan.js/
I think it's what Twitter and LinkedIn uses in production.
Here's a working example/tutorial on using NodeJS, ExpressJS and MustacheJS Template Engine:
http://devcrapshoot.com/javascript/nodejs-expressjs-and-mustachejs-template-engine
You can build out a complete web page like you normally would, placing the mustacheJS fields where you like. Use express to route to the page, use node fs.readFileSync(); to get the html file, use mustache to update the data on the page then spit it out to the client.
It's kinda neat. I hope it helps!
-A-
Have you already tried stache ? It is no longer maintained but you can follow some links and get more recent stuff ..
I found Handlebars.js which is an extension of the Mustache template system/language.
And there is a really simple wrapper to use it with Express.
Sure, the best way to do this is the post here:
http://iamtherockstar.com/blog/2011/11/21/using-mustache-templates-express-apps/
So far, this has worked great for me. The only problem I have found is not using partials at the root path for views. For example partials in view/partials - the engine by default only finds partials as view. Let me know if you figure that out!
Check out Handlerbars. " Handlebars provides the power necessary to let you build semantic templates effectively with no frustration.
Handlebars is largely compatible with Mustache templates. In most cases it is possible to swap out Mustache with Handlebars and continue using your current templates. Complete details can be found here " - Handlebars

Resources