DEV Community

Igor Bertnyk
Igor Bertnyk

Posted on

The ultimate guide to hosting multilingual Angular application on Google App Engine

Google App Engine is a good option to serve SPA applications, such as Angular. It requires little maintenance, can be easily auto-scaled if necessary, and you can extend it with CDN or load balancer. However, an Angular application requires several tricks to make it work properly. For example, to support deep links and browser refresh, routed apps must fallback to index.html. But navigation to the index page should happen only for routes, not for existing files and assets, so there should be exception for such things.
For localized, multilingual application that becomes even more complicated. Let's see why.
Internationalization (aka i18n) of the applications is often mandated for countries other than USA, and useful even there, if you want to make them accessible world-wide. To localize my app I have followed the official guide:
Localizing your Angular app
This is a fairly involved process that I will not describe here. Sufficient to say that after all preparations, translation of the resource files and changing of the build process, in your "dist" folder you will get a copy of your application for every language supported. So, for example, if you support English and French, in the "dist' folder there will be "en" and "fr" subfolders, each containing a full translated application.
In a typical multilingual application navigation to the different language is facilitated by URL prefix, e.g. "" will show the login page in French, so we need to map these URL patterns to the underlying application assets.
Let's quickly go through the build and deployment process and then we will see how to do that mapping.

As I mentioned, the build process is slightly changed:

npm run build -- --configuration=production --localize

To deploy to Google Cloud you need "gcloud CLI". If you are using CI/CD pipelines, it is often preinstalled on all major DevOps platforms and agents.
You'd need to authorize the CLI session, either manually, or with the help of the secret credentials file, which you can download from the GCP console (navigate to APIs & Services/Credentials).
This is a sample command:

gcloud auth activate-service-account --key-file=$(gcloud.secureFilePath)

Finally, to deploy your app to the App Engine, you can execute the following command:

gcloud app deploy --verbosity=info <path to your dist folder>/app.yaml --promote --stop-previous-version --quiet --project=<your GCP project ID>

Replace the values in angle brackets accordingly.

Now we get to the most important part: how to make our Angular app work on App Engine.
The magic resides in the "app.yaml" file, with the help of which we can overcome all of the obstacles I listed above.
The full reference can be found here, but for Angular we need just a subset of configuration options.
Several points to mention before I attach the full app.yaml file for your reference.

  • Remember that app.yaml should be in the root (dist) folder.
  • Python instance in Standard Environment is the simplest hosting option to set up.
  • Affinity is not required, as Angular package will be downloaded to the client, and sessions will be facilitated by the browser.
  • Downloaded javascript packages will be often cached on a client side, so usually we should not expect an extremely high load on our server.
  • We need to provide a fallback for all routes to the index.html page in the corresponding language.
  • Images, fonts, and other static assets should be exempted from the above rule.
  • It might be a good option to have a "landing page" from which the user can navigate to the language of choice, or it can automatically redirect the user based on the browser language settings.

And behold! A sample app.yaml file that you can freely reuse to host you Angular application on App Engine:

I hope that was helpful. Any comments on how to make this config even better are welcome. Here is a multilingual, French-speaking cat for you:
French-speaking cat
(Saved from

Discussion (0)