简体   繁体   English

NestJS 基于浏览器语言交付静态文件

[英]NestJS deliver static files based on language of browser

Nestjs should deliver an Angular application based on the language defined in the browser. Nestjs 应该提供基于浏览器中定义的语言的 Angular 应用程序。

The Angular application is located on dist/public/en or dist/public/de . Angular 应用程序位于dist/public/endist/public/de

If the user is accessing / with an English browser, nestjs should deliver files from folder dist/public/en .如果用户使用英文浏览器访问/ ,nestjs 应该从文件夹dist/public/en传送文件。 The path in the browser should point in this case to fqdn/en/ .在这种情况下,浏览器中的路径应该指向fqdn/en/

I already use this with single language Angular App:我已经在单语言 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.我还查看了i18next ,它看起来很有希望。

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.比静态提供dist文件夹更好的是将所有非 api 路由重定向到index.html以便您的 Angular SPA 可以处理路由。 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:您可以通过考虑要检测用户语言的因素(例如ACCEPT-LANGUAGE标头或某个 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. @kim-kern 非常感谢您的回答。 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:我现在通过以下方式解决了这个问题:maint.ts 将基于全局中间件进行语言检测并定义文件的静态交付:

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:我定义了一个自定义中间件,用于检查找到的语言,并根据 baseUrl 提供正确的 index.html 文件:

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:然后将自定义中间件包含在 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.现在唯一开放的问题是它总是尝试从固定目录 public 传递文件,如果在开发模式而不是生产模式下运行会失败。

I will search there for a solution for it.我会在那里寻找解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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