3

I'm trying to use Universal with i18n.
I'm already building the app and setting the server config so that once the app passes to browser-side mode the user is redirected to the correct translation of the app, that is fine.

The issue I'm having is in the server-side rendering.
With the way that the express server is set, I don't see how to provide the universal's server-side correct translation, and only the default language is being displayed instead of the local one.
Like with browser-side, I tried to have a different builds, one for each language, for the main.bundle file used by the server-side mode. Problem is, I can't set more than one of those files per app.

Dist folder structure:

dist/
  server.js
  browser/
    en/
      ...
    it/
      ...
  server/
    en/
      ...
      main.bundle // eng translation
    it/
      ...
      main.bundle // ita translation

server.ts file

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
// In this line I can only provide one file for the server-side translation,
// and I can't dynamically change it to the correct translation.
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = 
require("./dist/server/en/main.bundle"); 

app.engine("html", ngExpressEngine({
    bootstrap: AppServerModuleNgFactory,
    providers: [
        provideModuleMap(LAZY_MODULE_MAP),
    ],
}));

The server-side app is rendered from the main.bundle in the fourth line. However I don't get the possibility to provide one for each translation, how can I fix that?
My point is having Angular Universal provide the correct server-side translation of the app.

Stephen Docy
  • 4,738
  • 7
  • 18
  • 31
Kunepro
  • 418
  • 2
  • 4
  • 18
  • Will your site have 2 different urls for each page? `/en/home`, `/it/home`? If so, you can parse the url, decide which language to iuse and use the appropriate bunde accordingly – David Apr 03 '18 at 08:28
  • Yes, I have an url like you described per language. My question is exactly how to do what you just said, on the server-side rendering. – Kunepro Apr 03 '18 at 20:41

1 Answers1

3

I assume your urls are build like "/en/sample" for all english sites ("/en/" as base) and "/sample" for your italian sites (default, base "/"). If this assumption is incorrect adjust this code to your needs. Basically you want to build two seperate engines and use the correct one depending on the called url.

// import your bundles
const itBundle = require('./dist/server/it/main.bundle');
const enBundle = require('./dist/server/en/main.bundle');

// define your engines for it and en
// id is needed to find the path
// base is for routing see below
const languageEngines = [{
  id: 'en',
  base: '/en/',
  engine: ngExpressEngine({
    bootstrap: enBundle.AppServerModuleNgFactory,
    providers: [provideModuleMap(enBundle.LAZY_MODULE_MAP)]
  })
},
{
  id: 'it',
  base: '',
  engine: ngExpressEngine({
    bootstrap: itBundle.AppServerModuleNgFactory,
    providers: [provideModuleMap(itBundle.LAZY_MODULE_MAP)]
  })
}];

// Load your engine
app.engine('html', (filePath, options, callback) => {
  options.engine(
    filePath,
    { req: options.req, res: options.res},
    callback
  )
});

app.set('view engine', 'html');

// handle en file routes
app.get('/en/*.*', express.static('./dist/browser'));
// file routes for it
app.get('*.*', express.static('./dist/browser/it'));

// handle routes for each language
languageEngines.forEach(languageEngine => {
  app.get(`${languageEngine.base}*`, (req, res) => {
    res.render(`./dist/browser/${languageEngine.id}/index.html`, {
      req,
      res,
      engine: languageEngine.engine
    })
  })
});

If you have questions feel free to ask.

darron614
  • 893
  • 7
  • 15
  • Hi @darron614, I don't have a base empty url, as it redirects to "/en/". So it's "/en/" and "/it/", but I see how to fix that. I don't get what you are trying to do with: `res.render(...), {`. How come there's a comma there? I'm trying to replicate your solution, but I don't get that part. – Kunepro Apr 03 '18 at 20:44
  • 1
    I'm passing an object to the view . The important part is the engine. One of the engines previously defined will be used for the views. The english engine for /en/ routes and the italian engine for / routes. You can look at the documentation of res.render here: https://expressjs.com/en/api.html#res.render – darron614 Apr 03 '18 at 21:03
  • 1
    I'm sorry I had a typo in my solution. There was one bracket too much. It's supposed to be res.render(..., {...}) not res.render(...), {}) – darron614 Apr 03 '18 at 21:11
  • I tried again in the morning and got this to work both server and client side with some adjustments. I will post my changes later in the evening, Thank you! – Kunepro Apr 04 '18 at 06:21