Locale Support Prior to Angular 9
Since Angular 5, the framework has shipped with locale-specific meta data derived from the Unicode Common Locale Data Repository (CLDR). To use a particular locale, developers had to explicitly import and register it prior to application bootstrapping, typically inside main.ts:
import { registerLocaleData } from '@angular/common';
import localeDe from '@angular/common/locales/de';
import localeDeAt from '@angular/common/locales/de-AT';
import localeEs from '@angular/common/locales/es';
registerLocaleData(localeDe); // de-DE
registerLocaleData(localeDeAt); // de-AT
registerLocaleData(localeEs); // es-ES
[...]
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
The en-US locale has always been included by default without any additional setup.
This approach inevitably bloats the initial bundle, because all imported locale data is statically linked at build time. The following sections demonstrate how Angular 9 provides a more flexible alternative.
Understanding Global Locales
Starting with version 9, Angular ships dedicated bundles that assign locale meta data to the global.ng.common.locales object. For instance, German locale information would be stored under global.ng.common.locales['de']. Hence, the term "global locales."
You can find these bundles in the package directory node_modules/@angular/common/locales/global:

Global locales are closely tied to the new code>@angular/localize package, which significantly upgrades the built-in I18N pipeline. Its core concept is a single compilation of the app: you build the application exactly once, replicate the output for each target language, and then apply language-specific customizations to each copy.
These customizations include both text replacement and the injection of locale-specific formatting meta data. To accomplish the latter post-build, a straightforward mechanism for injecting this data is essential — which is exactly what global locales provide.
This strategy proves substantially more efficient than the previous method, which required recompiling the entire application once for each language.
In typical scenarios, you won't interact with global locales directly, as the Angular CLI handles them automatically behind the scenes. Those interested in exploring code>@angular/localize further can check out this excellent blog post.
That said, if your project relies on an alternative translation library like ngx-translate rather than code>@angular/localize, or if you use code>@angular/localize with runtime-loaded translation texts (fetched from a custom backend), then handling global locales manually becomes quite relevant.
In such scenarios, fetching only the meta data actually needed, rather than preloading everything, can markedly enhance initial load performance.
Implementing Lazy Loading
To illustrate manual lazy loading of global locales, I put together a compact sample app that starts in en-US:

Clicking the German Version button triggers the on-demand loading and activation of the German locale. To achieve this, I implemented a minimal script loader that dynamically constructs a script element:
//
// Simplest Possible Script Loader TM
//
@Injectable({
providedIn: 'root'
})
export class SimpleLoaderService {
constructor() { }
// Remeber already loaded files so that we
// don't load it again.
private loadedFiles = new Set<string>();
loadScript(src: string): Promise<void> {
// If the file is already loaded don't do anything.
if (this.loadedFiles.has(src)) {
return Promise.resolve();
}
return new Promise<void>((resolve, reject) => {
// Create a script tag and point to java script file
const script = document.createElement('script');
script.src = src;
// Resolve Promise after loading
script.onload = () => {
this.loadedFiles.add(src);
resolve();
};
// Reject Promise on error
script.onerror = () => {
reject();
};
// Add script tag to page
document.body.appendChild(script);
});
}
}
Within the demo's AppComponent, there's a date (coincidentally the author's birthday) and a property that tracks the currently active locale:
@Component({ [...] })
export class AppComponent {
date = new Date('2020-01-20T17:00+01:00');
lang = 'en-US';
constructor(private loader: SimpleLoaderService) {
}
toGerman() {
this.loader
.loadScript('assets/de.js')
.then(_ => this.lang = 'de-DE')
.catch(err => console.error('Error loading file', err));
}
}
The template renders this date accordingly:
{{ date | date:'long':'':lang }}
The toGerman method, wired to the button, employs the SimpleLoaderService to fetch the German locale and subsequently updates the lang property.
Verifying the Behavior
To confirm lazy loading is functioning, open Chrome's developer tools, navigate to the Network tab, and click the German Version button. You'll observe that assets/de.js is fetched at that moment, and the displayed date switches to a German-formatted version.

Final Thoughts
Additional Resources
- Comprehensive write-up on @angular/localize by Cédric Exbrayat
- Commit: Support loading locales from a global
- The demo project referenced here
Further Learning
To dive deeper into these advanced concepts, consider our Advanced Angular Workshop, focusing on enterprise-level architectures and sustainable practices.

