Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I 'ng serve' the original app after localizing it with @angular/localize?

I was playing with Angular's localization @angular/localize and after configuring it to translate the app to different language I tried to serve the default version of it using 'ng serve' but I get this error:

An unhandled exception occurred: The development server only supports localizing a single locale per build.

I tried it with different port based on this: How to serve different Angular locales during development using ng serve? but to no avail.

For the translated version everything works using 'ng serve --configuration=fr'. Builds work correctly creating 'en-US' and 'fr' folders in dist/App folder.

When I removed the inlineLocales.size condition in dev-server everything worked fine, no errors:

if (i18n.shouldInline && tsConfig.options.enableIvy !== false) {
    //if (i18n.inlineLocales.size > 1) {
    //    throw new Error('The development server only supports localizing a single locale per build');
    //}
    await setupLocalize(i18n, browserOptions, webpackConfig);
}

So it may be Angular-devkit issue.

I tried to work around by creating new "en-US" locale but got this error:

An unhandled exception occurred: An i18n locale ('en-US') cannot both be a source locale and provide a translation.

After using just 'en' instead of 'en-US' and creating new translation file with <source> and <target> translation being the same it works using 'ng serve --configuration=en' but it looks like a wrong solution.

Here is my angular.json:

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "App": {
      "projectType": "application",
      "i18n": {
        "sourceLocale": "en-US",
        "locales": {
          "fr": "src/locale/messages.fr.xlf"
        }
      },
      "schematics": {
        "@schematics/angular:component": {
          "style": "scss"
        },
        "@schematics/angular:application": {
          "strict": true
        }
      },
      "root": "",
      "sourceRoot": "src",
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "localize": true,
            "outputPath": "dist/App",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "aot": true,
            "assets": ["src/favicon.ico", "src/assets"],
            "styles": ["src/styles.scss"],
            "scripts": []
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "500kb",
                  "maximumError": "1mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "2kb",
                  "maximumError": "4kb"
                }
              ]
            },
            "fr": {
              "localize": ["fr"]
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "App:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "App:build:production"
            },
            "fr": {
              "browserTarget": "App:build:fr"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "App:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.spec.json",
            "karmaConfig": "karma.conf.js",
            "assets": ["src/favicon.ico", "src/assets"],
            "styles": ["src/styles.scss"],
            "scripts": []
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "tsconfig.app.json",
              "tsconfig.spec.json",
              "e2e/tsconfig.json"
            ],
            "exclude": ["**/node_modules/**"]
          }
        },
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "e2e/protractor.conf.js",
            "devServerTarget": "App:serve"
          },
          "configurations": {
            "production": {
              "devServerTarget": "App:serve:production"
            }
          }
        }
      }
    }
  },
  "defaultProject": "App"
}

How to reproduce: The app is generated using Angular CLI 10.0.0 and Angular 10.0.1 and then adding @angular/localize by 'ng add @angular/localize'. In app.component.html is single <h1 i18n="@@app.h1">Hello</h1>. Using the angular.json above.

like image 832
Theraggon Avatar asked Jun 30 '20 16:06

Theraggon


3 Answers

Set "localize": false in your example in your answer is equal to "localize": ["en"],

So...

While the accepted answer works it isn't the right answer since you shouldn't have your default behavior to be the one compilation to all the languages.

What you can do it to make a build for the language and call it, so eventually you will have:

     "architect": {
    "build": {
      "builder": "@angular-devkit/build-angular:browser",
      ....
      "configurations": {
        .......
        "fr": {
          "localize": ["fr"]
        },
        "en": {
          "localize": ["en"]
        },
      }
    },

"serve": {
        ...
        ...
        "fr": {
          "browserTarget": "App:build:fr"
        },
        "en": {
          "browserTarget": "App:build:en"
        }

      }
    },

Then when you do ng serve --configuration=en it would work, and you wouldn't need change the default build option to all of your other builds.

like image 186
Remy Avatar answered Sep 30 '22 12:09

Remy


In "options", you must set "localize" to false:

"architect": {
    "build": {
      "builder": "@angular-devkit/build-angular:browser",
      "options": {
        "localize": false,

and build again:

ng build
like image 43
mabg Avatar answered Sep 30 '22 13:09

mabg


No need to set localize: false. What is missing here is to add a couple of entries in your angular.json for your sourceLocale language, in this case en-US (even if you will not have a dedicated translation file for en-US).

Heading to angular.json, leave the configurations object like:

...
"fr": {
  "localize": ["fr"]
},
"en-US": {
  "localize": ["en-US"] << or whatever your sourceLocale is
},
...

Then:

"fr": {
  "browserTarget": "App:build:fr"
},
"en-US": {
  "browserTarget": "App:build:en-US" << or whatever your sourceLocale is
},

Now you should be able to:

ng serve --configuration=en-US

Or

ng serve --configuration=fr

Which you could simplify by editing your package.json scripts like:

"scripts": {
  "ng": "ng",
  "start": "ng serve --configuration=en-US",
  "start:fr": "ng serve --configuration=fr",
...

Now, npm run start will serve the app in English, and npm run start:fr will serve the French version.

like image 40
Erwol Avatar answered Sep 30 '22 12:09

Erwol