In the previous post, we discussed, Angular's localize package and how we can run separate locale configurations.
Here, we will discuss Angular Universal, a technology that renders Angular applications on the server and how it helps angular app to be accessible in different sub-directories, depending on the language.
First, we run the below CLI command
ng add @nguniversal/express-engine --clientProject=demoproject
Here, clientProject is our existing Angular application.This command generates server-side app module, app.server.module.ts and Express web server, server.ts . This web server is used to decide, as to which locale will be rendered for a particular request.
Next, We modify the Express web server to add the following code.
app.get('*', (req, res) => {
//this is for i18n
const supportedLocales = ['en', 'pa',...];//supported Locales
const defaultLocale = 'en';
const matches = req.url.match(/^\/([a-z]{2}(?:-[A-Z]{2})?)\//);
//check if the requested url has a correct format '/locale' and matches any of the supportedLocales
const locale = (matches && supportedLocales.indexOf(matches[1]) !== -1) ? matches[1] : defaultLocale;
res.render(`${locale}/index`, { req });
});
// Start up the Node server
app.listen(PORT, () => {
console.log(`Node Express server listening on http://localhost:${PORT}`);
});
Through this modification, web server identifies the locale of the request, and renders the response accordingly.
You will notice that, in angular.json, server Configurations is automatically added once you run ng add @nguniversal/express-engine
command, which looks like below.
"server": {
"builder": "@angular-devkit/build-angular:server",
"options": {
"outputPath": "dist/server",
"main": "src/main.server.ts",
"tsConfig": "src/tsconfig.server.json"
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
]
},"pa-Guru": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
]
},
"en-US": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
]
}
}
In package.json, add/modify below scripts according to your project to build and render all locales of your app.
"compile:server": "webpack --config webpack.server.config.js --progress --colors",
"serve:ssr": "node dist/server",
"build:ssr": "npm run build:client-and-server-bundles && npm run compile:server",
"build:client-and-server-bundles": "ng build --configuration=pa-Guru && ng build --configuration=en-US && ng run demoproject:server:production && ng run demoproject:server:en-US && ng run demoproject:server:pa-Guru"
Finally, you can run the following command on Angular CLI to render locales through express server and change locales on runtime, depending on the request Url's baseHref.
npm run build:ssr && npm run serve:ssr
Benefits of using Server Side Rendering
Search Engines and social media sites rely on web crawlers to index your application content and make that content searchable on the web. These web crawlers may be unable to navigate and index your highly interactive Angular application as a human user could do.
Angular Universal can generate a static version of your app that is easily searchable, linkable, and navigable without JavaScript. Universal also makes a site preview available since each URL returns a fully rendered page.
We serve a static version of the landing page to hold the user's attention. At the same time, we'll load the full Angular app behind it. The user perceives near-instant performance from the landing page and gets the full interactive experience after the full app loads.
Motivation for using Angular i18n over other available libraries
First, we look at some of the disadvantages.
- Angular i18n only works with one language at a time, you have to completely reload the application to change the language.
- Angular i18n only supports using i18n in your templates for now.
But, its Advantages overpower the drawbacks.
- Angular i18n supports ICU expressions (plurals and select).
- The translation process is well defined, it is easy to detect missing translations and you can integrate that in your plans before deploying your app (extract, send to translators, merge).
- It scales well, you never look directly at the files since you use a software for that, you can translate in x languages, you just need to extract once and create the translation files for each locale (which your professional tool should do for you)
- It's super efficient because the app is pre-translated when it bootstraps, there's no extra work to apply your translations and * It works well with pre-rendering because of that since you merge the translations at build time, it means that it can support directives, components and other html elements, you can move them around in the different languages, or even remove them if needed
- You don't need to worry about lazy loading, your bundles are translated at build time, and that includes your lazy loaded modules.
Thanks for your time. Please share and provide reactions if you like the blog.
Top comments (5)
Did anyone try this on Angular 13? Just trying to serve or build SSR gives me an error when trying to run the server:
ng run app:server
./node_modules/node-webcrypto-ossl/build/Release/nodessl.node:1:0 - Error: Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
Sorry for delay in response. I did this in Angular 7. Not sure about Angular 13.
No worries, I actually discovered that one of my dependencies did now allow for server side compilation, and that was the issue for me.
Cheers
Keep up the good work ..
Awesome thanks.. i18n is insanely good on Angular, but never found how to render multiple locales om server. Thanks