12

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.

Theraggon
  • 123
  • 1
  • 7

4 Answers4

9

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.

Remy
  • 1,053
  • 1
  • 19
  • 25
  • You can simplify this by adding ",en-US" or whatever your default locale is set to to the browserTarget for development. `"projects.[your-proj-name].architect.serve.configurations.development.browserTarget"` becomes `"[your-proj-name]:build:development,en-US"` You also need the `".build.configurations.en-US"` entry as shown above with "en" Then the default "npm start" or "ng serve" will use this locale explicitly. No need to change package.json for that. – Rocco Mar 31 '23 at 08:17
6

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.

Erwol
  • 1,911
  • 2
  • 23
  • 28
  • You can also combine multiple configurations with a comma. Specifically for `serve`, though, I found I had to do it with browser-target instead, like `ng serve myapp --browser-target=myapp:build:local,en-US --open --port=4200` or `ng serve myapp --browser-target=myapp:build:local,es-MX --open --port=4201`. This would use both my "local" configuration and the right culture's config together. See [this](https://github.com/angular/angular-cli/issues/17473#issuecomment-641078028). – Roobot Jun 15 '21 at 22:57
2

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

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

and build again:

ng build
mabg
  • 1,894
  • 21
  • 28
  • 3
    You should not change angular.json back and forth just to work with different locales – engilyin Dec 29 '21 at 22:17
  • You don't have to "change angular.json back and forth"... You can set `localize` to false for the specific environment under configurations. i.e under architect -> configurations -> development (Assuming you don't use the actual localization during development) – Tjad Clark Jun 30 '22 at 04:42
2

I'm using Angular 15 and I had the same problem, but I solved it by using a comma instead of a colon inside browserTarget. I didn't even change localize to false and after running ng serve --configuration=en-US and ng serve --configuration=fr they both worked like a charm !

NB: This question is repeated here : An unhandled exception occurred: The development server only supports localizing a single locale per build

"serve": {
      "builder": "@angular-devkit/build-angular:dev-server",
      "configurations": {
        "fr": {
          "browserTarget": "myApp:build:development,fr"
        },
        "en-US": {
          "browserTarget": "myApp:build:development,en-US"
        },
        "production": {
          "browserTarget": "myApp:build:production"
        },
        "development": {
          "browserTarget": "myApp:build:development"
        }
      },
      "defaultConfiguration": "development"
    },
Samuel
  • 31
  • 4