Skip to content

Instantly share code, notes, and snippets.

@jamuhl
Created January 13, 2016 07:35
Show Gist options
  • Save jamuhl/f8020960024b4d09f721 to your computer and use it in GitHub Desktop.
Save jamuhl/f8020960024b4d09f721 to your computer and use it in GitHub Desktop.
i18next - multiple express apps
var i18next = require('i18next');
var middleware = require('i18next-express-middleware');
var Backend = require('i18next-node-fs-backend');
var express = require('express');
i18next
.use(Backend)
.init({
// use correct configuration options...look up docs!
backend: {
loadPath: __dirname + '/locales/{{lng}}/{{ns}}.json'
}
});
// pseudo virtual hosts
var vhosts = [
{ lng: 'de', port: 3000 },
{ lng: 'en', port: 3001 }
];
vhosts.forEach(function(host) {
var app = express();
// set req.lng to defined lng in vhost
// see for details:
// https://github.com/i18next/i18next-express-middleware/blob/master/src/index.js#L14
app.use(function(req, res, next) {
req.lng = host.lng;
next();
});
// use the middleware to do the magic
// create a fixed t function for req.lng
// no clones needed as they just would do the same (sharing all but lng)
app.use(middleware.handle(i18next));
// in your request handler
app.get('/', function(req, res) {
var lng = req.language;
var lngs = req.languages;
console.log('language is: ', lng, lngs);
res.send(req.t('key1'));
});
app.listen(host.port);
});
// go to localhost:3000 ---> de
// go to localhost:3001 ---> en
// unclear to me...why you need an array of express apps to archive this.
// one app with custom language detector function detection lng from domainName
// would be enought to detect lng and translate content appropriate
@uroblesmellin
Copy link

Hi,

Yes, of course we want to translate all handlebar (we are using handlebars as our template library) references in a given page for a given host. We are defining a handlebars helper called "i18n" that actually calls your t method:

var boltHelpers = {
    helpers : {
        // Handlebars helper from i18next
        'i18n' : function(i18n_key) {
            var result = _i18n.t(i18n_key);
            return result;
        }
    }
};

For instance, say in index.hbs we have

<h1>{{i18n "title"}}</h1>

{{i18n "title"}} should become the corresponding value given in the file en_US/translations.json or fr_FR/translations.json, etc.

My point was that we are not translating anything in the loop that is setting up the app for a given host (the code shown above). There we don't need to translate a key to get a value, just to set or initialize the i18next instance. We are using handlebars to then read the translated value when a page gets loaded. That's working fine with:

app.use(function(req, res, next) {
i18next.changeLanguage(host.lng);
next();
});

So {{i18n "title"}} will become something like "Hello World" or "Hallo Welt"

Originally, I tried with:

app.use(function(req, res, next) {
req.lng = host.lng;
next();
});

But that just rendered "title" in the html output, not the corresponding localized value.

I do see the point of your comment of not using i18next.changeLanguage(host.lng); because it could yield concurrency issues. The only reminding issue to solve is how to attach the host.lng (the language of the current host) to the "instance of i18next" for that host.

Thanks for your time!

@jamuhl
Copy link
Author

jamuhl commented Jan 16, 2016

your issue is related to handlebars being a singleton!

see http://stackoverflow.com/questions/17274142/setting-a-handlebars-helper-to-return-a-specific-value-per-request-in-express

// change the order - first the middleware to get req.t
app.use(middleware.handle(i18next));

// set your lng
// add handlebars helper
app.use(function(req, res, next) {
  req.lng = host.lng; 

  // not sure how you assert in handlebars request save functions...as i always used jade on server
  // which does not suffering from the singleton problem 
  // t helper will be dangerous as race conditions on requests can overwrite it
  // see http://stackoverflow.com/questions/17274142/setting-a-handlebars-helper-to-return-a-specific-value-per-request-in-express
  var handlebars = new ???;
  handlebars.registerHelper('t', function(key, options) {
    var result = req.t(key, options.hash);
    return new handlebars.SafeString(result);
  });

  next();
});

@uroblesmellin
Copy link

Thanks Jan.

The problem is that req.t is undefined:

app.use(function(req, res, next) {
req.lng = host.lng;

// not sure how you assert in handlebars request save functions...as i always used jade on server
// which does not suffering from the singleton problem
// t helper will be dangerous as race conditions on requests can overwrite it
// see http://stackoverflow.com/questions/17274142/setting-a-handlebars-helper-to-return-a-specific-value-per-request-in-express
var handlebars = new ???;
handlebars.registerHelper('t', function(key, options) {
var result = req.t(key, options.hash); // <========== req.t is undefined.
return new handlebars.SafeString(result);
});

next();
});

We still need a way to retrieve the i18next instance. Going back to the original question. req.t === undefined.

Thanks

@jamuhl
Copy link
Author

jamuhl commented Jan 22, 2016

req.t === undefined --> gets set by app.use(middleware.handle(i18next));

@uroblesmellin
Copy link

Hi Jan,

I get this error just by placing this line before as you mentioned:

// change the order - first the middleware to get req.t
app.use(middleware.handle(i18next));

If I do that before :
app.use(function(req, res, next) {
// ...
});

I get:

TypeError: Cannot read property 'indexOf' of undefined
at e.a.value (/Users/uroblesmellin/projects/bolt20-frontend/bolt-2dot0-frontend/node_modules/i18next/bin/index.js:1:13811)
at t.u.value (/Users/uroblesmellin/projects/bolt20-frontend/bolt-2dot0-frontend/node_modules/i18next/bin/index.js:2:8308)
at /Users/uroblesmellin/projects/bolt20-frontend/bolt-2dot0-frontend/node_modules/i18next-express-middleware/lib/index.js:82:40
at Layer.handle as handle_request
at trim_prefix (/Users/uroblesmellin/projects/bolt20-frontend/bolt-2dot0-frontend/node_modules/express/lib/router/index.js:312:13)
at /Users/uroblesmellin/projects/bolt20-frontend/bolt-2dot0-frontend/node_modules/express/lib/router/index.js:280:7
at Function.process_params (/Users/uroblesmellin/projects/bolt20-frontend/bolt-2dot0-frontend/node_modules/express/lib/router/index.js:330:12)
at next (/Users/uroblesmellin/projects/bolt20-frontend/bolt-2dot0-frontend/node_modules/express/lib/router/index.js:271:10)
at /Users/uroblesmellin/projects/bolt20-frontend/bolt-2dot0-frontend/server/middlewares/write-header.js:9:9
at Layer.handle as handle_request

If I do it in the original way (without changing the order of

app.use(middleware.handle(i18next));

I don't get that error.

Thanks,
Ulises

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment