5

Overview

I have Angular 6 app build by Angular CLI. Application is written in multiple languages. Each language has JSON file with translations of all the application texts. The filenames are ${language}.json, e.g. en.json, es.json, pl.json.

I'd like to set the language of the app during build - build the app only in one language. For that on build I need to import a single translation file, which is chosen depending on which language I'm building for.

Problem

How to conditionally import single translation file only for the language chosen during build?

In addition I'd like the translation file to be bundled together with the rest of my application's JavaScript, instead of being loaded on demand on run-time.

Sketch of a solution

const translations = import(`./translations/${lang}.json`);

Actually the above code works in Angular 6/Webpack (the only thing needed is setting compilerOptions.module: 'ESNext' in tsconfig.app.json), but not in a way that I want. Instead of resolving the import during build time and bundling the translation file together with the rest of the code, it creates a separate files (chunks) for all translations, one of which is then loaded on demand during run-time depending on the value of JavaScript lang variable.

So how do I make the import to be resolved during build-time and not run-time? Also where and how do I set lang variable during build, as I don't have access to Webpack configuration (it's hidden inside Angular CLI)

Webpack alone

When using Webpack alone, it's possible to implement this for example by using NormalModuleReplacementPlugin. But as Angular CLI hides all the Webpack configuration, I don't know how to integrate it into Angular project. Ejecting Webpack configuration from Angular CLI is the last resort for me.

Robert Kusznier
  • 6,471
  • 9
  • 50
  • 71
  • From what I've read, conditional `imports` can only be done with the `ESNext` module flag, and that process creates a chunk that is imported at runtime. You might actually need to run a pre-build script to replace the `.json` file before the Angular bundling/build step – Drenai Aug 28 '18 at 10:05
  • @Drenai By "can only be done" you mean when using Angular framework without ejecting Webpack configuration or generally in Webpack? Because conditional imports resolved on build-time are possible in Webpack. I just don't know how to implement that in Angular without ejecting the whole Webpack configuration. – Robert Kusznier Aug 28 '18 at 10:13
  • 1
    Yes, without ejecting. There might be another way though. In Angular CLI v6.1 (maybe beta), there was a new feature added that allows adding our own `fileReplacements`, based on the configuration we supply in the build step. It use to only work with `.ts` files, but it's been updated to work with any files https://github.com/angular/angular-cli/issues/10881 – Drenai Aug 28 '18 at 10:19
  • @Drenai I think `fileReplacements` option is just what I need. Wasn't aware of it. If you want to work it out into a full answer, I'll gladly accept it. – Robert Kusznier Aug 28 '18 at 10:24
  • Ok, I'll do that now:-) – Drenai Aug 28 '18 at 10:31
  • Can you confirm if this actually works? [I've asked a similar question](https://stackoverflow.com/questions/50929946/angular-how-to-add-a-unique-htaccess-file-per-configuration/), so I can update the answer. – Jeffrey Roosendaal Aug 28 '18 at 11:37
  • I will confirm. Give me an hour or two, cause I've had a break and I still need to work-out how to specify configurations in Angular. – Robert Kusznier Aug 28 '18 at 12:40
  • 1
    @JeffreyRoosendaal I can confirm it works, but I still can't wrap my head around how to write those configurations, so to keep default `production` configuration, create separate configuration for each locale, while also being able to build that locale with `production` configuration, not copying and pasting the same configuration block for `productionEn`, `productionFr` etc. – Robert Kusznier Aug 28 '18 at 14:17
  • 1
    @RobertKusznier Thanks for confirming! Well, that's what I do, and it works fine, just copypaste the default configuration and change a line a or two. To make building easier, add this to each config: `"outputPath": "dist/productionName/"`, and add this to package.json's scripts: `"build:all": "ng build --configuration=production && ng build --configuration=productionEn && ng build --configuration=productionFr`. Type `npm run build:all` in the terminal, and sit back and enjoy ;) – Jeffrey Roosendaal Aug 28 '18 at 14:27
  • @JeffreyRoosendaal: My problem with configurations is not building them all, but writing the configurations in `angular.json` without repeating myself. `productionFr` and `productionEn` share most of the config, just differ in one file replacement. Also they include config from `fr` and `en` respectively. So far the only way to write `productionFr`, `productionEn`, `fr` and `en` is to copy and paste common parts, duplicating them. It'd be best to specify only 3 separate configurations: `fr`, `en`, `production` and switch them on and off during build, e.g. `--configuration=en,production`. – Robert Kusznier Aug 28 '18 at 15:18
  • I created a question about this problem [here](https://stackoverflow.com/questions/52061748/is-there-a-way-to-extend-configurations-in-angular-json). – Robert Kusznier Aug 28 '18 at 15:45

1 Answers1

3

As part of the CLI 6.1 release, a feature was added that allows files to be replaced during the build other than .ts files. Previously this was used for the environment and environment.prod files

Additional files can now be set with the fileReplacements key of the angular.json configurations. As far as I know, it should work with asset files, so .json should work. It's only been added recently, but there are issues/feature details that you can look up

Let us know if it works out!

P.S. If you don't want to complicate the angular.json configuration, you could create a .js node script, and run it before doing the build, passing in the language as a param, and replacing the relevant .json file in before building the Angular bundles

Drenai
  • 11,315
  • 9
  • 48
  • 82
  • 1
    I confirm it works, but am still working out how to cleanly write configurations. The important point in the issue you linked to is that you may have to update `@angular-devkit/build-angular` and `@angular/cli` packages for it to work. – Robert Kusznier Aug 28 '18 at 15:09