简体   繁体   中英

NestJS deliver static files based on language of browser

Nestjs should deliver an Angular application based on the language defined in the browser.

The Angular application is located on dist/public/en or dist/public/de .

If the user is accessing / with an English browser, nestjs should deliver files from folder dist/public/en . The path in the browser should point in this case to fqdn/en/ .

I already use this with single language Angular App:

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  app.useStaticAssets(join(__dirname, 'public'));
  await app.listen(process.env.PORT || 3000);
}
bootstrap();

I also had a look into i18next which looks promising.

But I'm not really sure if this is the right direction to go.

Any tip is warmly welcome.

Better than serving your dist folder statically would be to redirect all non-api routes to index.html so that your Angular SPA can take care of the routing. See this answer for more details.


You can adapt the middleware from the linked answer above by taking the factors into account with which you want to detect the user's language eg the ACCEPT-LANGUAGE header or a certain cookie:

@Middleware()
export class FrontendMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: Function) {
    // Some way of detecting the user's language
    const languages = req.header('ACCEPT-LANGUAGE') || 'en-US';

    if (languages.contains('de-DE')) {
      res.sendFile(join(__dirname, 'public', 'de' ,'index.html'));
    } else {
      res.sendFile(join(__dirname, 'public', 'en', 'index.html'));
    }
  }
}

@kim-kern thanks a lot for your answer. It pushed me into the right direction.

I solved the problem now the following way: maint.ts will do language detection based on a global middleware and defines a static delivery of files:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as compression from 'compression';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';
const i18next = require('i18next');
const middleware = require('i18next-http-middleware');

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  i18next.use(middleware.LanguageDetector).init({
    detection: {
      order: ['path', 'session', 'querystring', 'cookie', 'header'],
    },
  });

  app.use(
    middleware.handle(i18next, {
      ignoreRoutes: ['/api'],
      removeLngFromUrl: false,
    }),
  );

  app.useStaticAssets(join(__dirname, 'public'));
  app.use(compression());
  await app.listen(process.env.PORT || 3000);
}
bootstrap();

I defined a custom middleware that checks for the found language and based on the baseUrl it delivers the correct index.html file:

import { NestMiddleware, Injectable } from '@nestjs/common';
import { Request, Response } from 'express';
import { join } from 'path';

@Injectable()
export class FrontendMiddleware implements NestMiddleware {
  use(req: any, res: Response, next: Function) {
    if (req.lng && !req.baseUrl && req.lng.startsWith('de')) {
      res.sendFile(join(__dirname, 'public', 'de', 'index.html'));
    } else if (!req.baseUrl) {
      res.sendFile(join(__dirname, 'public', 'en', 'index.html'));
    } else {
      next();
    }
  }
}

The custom middleware is then included in the app.module.ts:

...
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer): void {
    consumer.apply(FrontendMiddleware).forRoutes({
      path: '/**',
      method: RequestMethod.ALL,
    });
  }
}

The only problem that is open is now that it tries to deliver the files always from the fixed directory public which fails if running in development and not production mode.

I will search there for a solution for it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM