AWS Cloudfront distribute multilingual angular apps

那年仲夏 提交于 2019-12-03 19:00:03

I've recently bumped into the same problem. My situation:

Solution:

  • Create 2 separate deployments, 1 for each language (en, fr). Git bash tends to replace the /en/ with a local folder, so make sure your index.html file contains the right base url

ng build -prod -aot --base-href /en/ --i18nFile=src/locale/messages.en.xlf --i1nFormat=xlf --locale=en

  • Deploy these into an /en/ and /fr/ folder at the root of your S3 bucket
  • Create a new CloudFront distribution. Make sure to leave the Default Root Object empty!
  • Add your bucket as an S3 origin (as you otherwise would).
  • Now, create a new Lambda function, use Node 6.10. Important: select US-EAST-1, as this is the only region supported by Lambda@Edge. Code:

const path = require('path')

exports.handler = (evt, ctx, cb) => {
  const { request } = evt.Records[0].cf

  if (!path.extname(request.uri)) {
      if (request.uri.startsWith('/fr'))
        request.uri = '/fr/index.html'
      else
        request.uri = '/en/index.html'
  }
  cb(null, request)
}
  • Next: publish this version (in the Action dropdown)
  • Copy the ARN of this version, and go back to CloudFront -> Behaviors -> Default Behavior
  • Select Origin Request as Event Type in the Lambda Function Associations, and paste the ARN of the Lambda function.

Building Angular with the base path parameter will establish the right subdirectory for your Angular app. The rewrite will make sure that resource files will not be rewritten, but all your routes will be redirected to index.html

I had the same problem but also wanted automatic redirection to the closest language when going to

<mydomain>.com/

Using Dries Van Hansewijck's solution and npm's locale package you can had redirection with the following code:

const path = require('path');
const locale = require("locale");
const supportedLocales = new locale.Locales(['en', 'de']);
locale.Locale["default"] = new locale.Locales('de');

module.exports.pendixPortalI18n = (event, context, callback) => {
  const { request } = event.Records[0].cf;
  const locale = getBestLocale(request);
  if (!path.extname(request.uri)) {
    console.log(JSON.stringify(event, null, 2));
    if (request.uri.startsWith('/en')) {
      console.log('ENGLISH detected')
      request.uri = '/en/index.html';
    } else if (request.uri.startsWith('/de')) {
      console.log('GERMAN detected')
      request.uri = '/de/index.html';
    } else {
      console.log('Default matching locale is ' + locale);
      request.uri = `/${locale}/index.html`;
    }
  }
  callback(null, request)
};

function getBestLocale(request) {
  /* First we try to find the accept-language value */
  if (request && request.headers
    && request.headers['accept-language'] && request.headers['accept-language'].length > 0
    && request.headers['accept-language'][0].value) {
    const acceptLanguage = request.headers['accept-language'][0].value;
    const locales = new locale.Locales(acceptLanguage);
    const bestMatch = locales.best(supportedLocales);
    console.log("You asked for: " + JSON.stringify(acceptLanguage));
    console.log("We support: " + supportedLocales);
    console.log("Our default is: " + locale.Locale["default"]);
    console.log('best match is ' + bestMatch);
    return bestMatch;
  }
  return 'de';
}

Here we try to find the user's language in the supported language list. In order to do that you need to forward the accept-language header to the origin in cloudfront (in the behavior tab). If the user's language is not in the supported languages list we redirect to german.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!