I am using i18n with Angular Universal SSR. The issue is that the client received the text in source locale and after a few seconds are replaced with the correcty locale.
For example, client load http://localhost:4000/en-US/ in the first display shows in es locale and after a few seconds the text is replaced with en-US locale texts.
The build folders are created correctly and the proxy works perfect for each locale. I want the server to return the html with the correct translation so the SEO crawlers can find the content correctly in each locale.
It seems that the problem is in the build, is not generated with the correct locale.
The proyect config in angular.json file:
...
"i18n": {
"sourceLocale": "es",
"locales": {
"en-US": {
"translation":"src/i18n/messages.en.xlf",
"baseHref": "en-US/"
}
}
},
...
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"outputPath": "dist/web/browser",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": true,
"localize": true,
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": [],
"customWebpackConfig":{
"path": "./webpack.config.js"
}
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
]
}
},
...
}
The command to build the proyect:
ng build --prod --configuration=production && ng run web:server:production
Build directories result in path dist/web/browser:
en-US/
es/
server.ts
file:
export function app(lang: string): express.Express {
const server = express();
server.use(compression());
const distFolder = join(process.cwd(), `dist/web/browser/${lang}`);
const indexHtml = 'index.html';
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
extraProviders: [{ provide: LOCALE_ID, useValue: lang }],
} as any));
server.set('view engine', 'html');
server.set('views', distFolder);
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}));
server.get('*', (req, res) => {
console.log(`LOADING DIST FOLDER: ${distFolder}`)
console.log(`LOADING INDEX: ${indexHtml}`)
res.render(`${indexHtml}`, {
req,
res,
providers: [
{ provide: APP_BASE_HREF, useValue: req.baseUrl },
{ provide: NgxRequest, useValue: req },
{ provide: NgxResponse, useValue: res }
]
});
});
return server;
}
function run(): void {
const port = process.env.PORT || 4000;
// Start up the Node server
const server = express();
const appEs = app('es');
const appEn = app('en-US');
server.use('/en-US', appEn);
server.use('/es', appEs);
server.use('', appEs);
server.use(compression());
server.use(cookieparser());
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run();
}
export * from './src/main.server';
2
Answers
After a few research I found the best solution. In order to made the server send the view with the proper translate you need to add a proxy file and create servers for each locale.
Enable i18n for servers with localize flag in true:
Create proxy-server.js:
server.ts:
The server is likely serving the static file first by default. To get around that you should change the name of index.html to index.origial.html in the dist folder.
In your
server.ts
fileSo the result will be that your ‘es’ version is then called index.original.html and the secondary version will become the new static version in
index.html
will be served first.