With the Angular CLI localize option, what does building en-US, de and ja variants produce, and how are those variants served?
answer
- compile once, then translate per locale
- one directory per locale
- base href follows the sub-path
- dev server handles a single locale
- root redirect by language header
basics
~20 sThe CLI compiles the app once, then inlines each locale's translations into a separate copy with its own directory, base href, html lang, LOCALE_ID and locale data. A server or Angular SSR redirects the root to the best-matching locale sub-path.
solid answer
~40 sWith `"localize": true` (or `ng build --localize`), the build compiles once, where `i18n` markers have already become `$localize` calls, and then runs a **translation inliner** per locale that replaces each `$localize` call with the translated literal. Each variant is a complete app in its own directory named by the locale's `subPath` (the locale code unless configured), with its `<base href>` adjusted to that path, `<html lang>` set, `LOCALE_ID` resolved to the locale, and its locale data included. `localize` can also be an array to build a subset. The dev server only localizes one locale per build, so you serve with a single-locale configuration. In production you serve `/en-US/`, `/de/` and `/ja/` and redirect the root, typically on `Accept-Language`; Angular's server rendering does that redirect automatically when `outputMode` is `server`.
code
json · 28 lines{
"projects": {
"shop": {
"i18n": {
"sourceLocale": "en-US",
"locales": {
"de": "src/locale/messages.de.xlf",
"ja": "src/locale/messages.ja.xlf"
}
},
"architect": {
"build": {
"builder": "@angular/build:application",
"options": { "localize": true },
"configurations": {
"de": { "localize": ["de"] }
}
},
"serve": {
"builder": "@angular/build:dev-server",
"configurations": {
"de": { "buildTarget": "shop:build:de" }
}
}
}
}
}
}go deeper
Recall that the localize option produces one complete copy of the app per locale, each in its own folder.
Explain compile once then inline per locale, and what each variant gets: sub-path, base href, html lang, LOCALE_ID and locale data.
Plan serving: deep-link fallbacks per sub-path, the root redirect, and the single-locale dev-server configuration the team works with.
Weigh build time, deploy size and page-load language switching against runtime translation as the number of locales grows.
## The goal A shop ships three languages: `en-US` (the source locale), `de` and `ja`. Angular's default approach is **compile-time translation**: every language gets its own fully translated copy of the app, so no translation work happens in the browser. ## What the build does 1. **Compile once.** The Angular compiler turns every `i18n` marker into a `$localize` tagged string. This step does not depend on the locale. 2. **Inline per locale.** For each requested locale, the translation inliner replaces every `$localize` call with the translated string literal from that locale's translation file, and replaces the `$localize.locale` read with the locale ID. 3. **Assemble each variant.** For every locale the CLI writes a complete copy of the app and: - puts it in a directory named by the locale's `subPath`, which defaults to the locale code; - sets the HTML `<base href>` by joining the configured base href with that sub-path; - sets the `lang` attribute of `<html>`; - includes and registers the locale data, so `LOCALE_ID` and the pipes work without code. The merge guide sums it up as "compile once, then translate for each locale", which is why adding a locale costs an inlining pass, not a full recompile. ## Choosing which locales to build | `localize` value | Result | | --- | --- | | `true` | Every locale defined in the project's `i18n` section | | `["de"]` | Only the listed locales | | `false` | No localization; the source locale only | A typical output layout for the three-locale shop: ```text dist/shop/browser/ en-US/index.html <base href="/en-US/"> <html lang="en-US"> de/index.html <base href="/de/"> <html lang="de"> ja/index.html <base href="/ja/"> <html lang="ja"> ``` Two configuration details interviewers probe: - `subPath` sets both the URL segment and the output directory name. An empty `subPath` for the source locale serves it from the root. - `subPath` and `baseHref` cannot be set together for the same locale; with server rendering, the CLI warns that a per-locale `baseHref` may behave unpredictably and recommends `subPath`. ## Development The dev server only localizes **one locale per build**. If `localize` is `true` or lists several locales, `ng serve` logs a warning and disables localization. To work on the German UI, create a configuration with `"localize": ["de"]` and serve that configuration. ## Serving the variants Each variant is an ordinary static app under its sub-path. The server needs two rules: - **Deep links:** requests under `/de/` fall back to `/de/index.html`, and likewise for the other locales. - **Root redirect:** a request for `/` is redirected to a locale, usually chosen from the `Accept-Language` header with the source locale as the fallback. With Angular's server rendering and `outputMode` set to `server`, the server engine redirects the base path to the preferred supported locale from `Accept-Language` itself, with a temporary (302) redirect and `Vary: Accept-Language`. Switching language in the UI means navigating to the other sub-path, which loads a different app. There is no live language switch within one page. ## Tradeoffs - **Pros:** no runtime translation cost, each bundle contains only its own language, and every variant is independently cacheable. - **Cons:** build time and deploy size grow with the number of locales, a language switch is a full page load, and the server must route sub-paths correctly.
- Why can the Angular CLI add a locale without recompiling the whole app?Compilation turns every `i18n` marker into a `$localize` call independent of language. Each locale is then produced by an inlining pass that swaps those calls for translated literals, so the expensive compile runs once and each additional locale costs only its own inlining and output.
- What must the web server do so a deep link like /de/cart works for the German variant?Route unknown paths under `/de/` to `/de/index.html`, the German variant's entry page. The page's base href is `/de/`, so the router resolves `cart` inside the German app. Without that fallback, the server returns a 404 for any non-root German URL.
saying these in an interview costs you the question
- The CLI does a full recompile for every locale
- One bundle holds all languages and switches at runtime
- ng serve can serve every locale at once
- Each variant still needs a manual LOCALE_ID provider
- subPath only renames the folder, not the base href