Reactive locale management with built-in support for 15+ languages, component-specific locale data, and comprehensive internationalization infrastructure for Angular applications.
Core locale management service with reactive data updates and Signal-based API.
/**
* Locale management service with reactive data
* Provides centralized locale data management and change notifications
*/
class DelonLocaleService {
/** Observable stream of locale data changes */
readonly change: Observable<FullLocaleData>;
/** Current locale data */
locale: FullLocaleData;
/** Set new locale data and notify subscribers */
setLocale(locale: FullLocaleData): void;
/** Get specific locale data by key */
getData<K extends keyof FullLocaleData>(key: K): FullLocaleData[K];
/** Get locale data as Angular Signal */
valueSignal<K extends keyof FullLocaleData>(key: K): Signal<FullLocaleData[K]>;
}Usage Examples:
import { Component, inject, OnInit } from "@angular/core";
import { DelonLocaleService } from "@delon/theme";
@Component({
selector: "locale-manager",
template: `
<div class="locale-controls">
<h3>Current Locale: {{ currentLocaleName }}</h3>
<div class="language-switcher">
<button
*ngFor="let lang of availableLocales"
(click)="switchLocale(lang.key)"
[class.active]="currentLocaleName === lang.name"
>
{{ lang.name }}
</button>
</div>
<div class="locale-data-preview">
<h4>Exception Messages:</h4>
<p>403: {{ exceptionData().403 }}</p>
<p>404: {{ exceptionData().404 }}</p>
<p>500: {{ exceptionData().500 }}</p>
<h4>Table Texts:</h4>
<p>Filter: {{ tableData().filterTitle }}</p>
<p>Reset: {{ tableData().filterReset }}</p>
<p>Confirm: {{ tableData().filterConfirm }}</p>
</div>
</div>
`
})
export class LocaleManagerComponent implements OnInit {
localeService = inject(DelonLocaleService);
currentLocaleName = 'English';
// Use signals for reactive locale data
exceptionData = this.localeService.valueSignal('exception');
tableData = this.localeService.valueSignal('st');
availableLocales = [
{ key: 'en_US', name: 'English' },
{ key: 'zh_CN', name: '简体中文' },
{ key: 'zh_TW', name: '繁体中文' },
{ key: 'ja_JP', name: '日本語' },
{ key: 'ko_KR', name: '한국어' },
{ key: 'fr_FR', name: 'Français' },
{ key: 'es_ES', name: 'Español' },
{ key: 'de_DE', name: 'Deutsch' }
];
ngOnInit() {
// Listen to locale changes
this.localeService.change.subscribe(newLocale => {
console.log('Locale changed:', newLocale);
this.updateCurrentLocaleName(newLocale);
});
}
async switchLocale(localeKey: string) {
try {
// Dynamically import locale data
const localeData = await this.loadLocaleData(localeKey);
this.localeService.setLocale(localeData);
// Update current locale name
const locale = this.availableLocales.find(l => l.key === localeKey);
this.currentLocaleName = locale?.name || 'Unknown';
} catch (error) {
console.error('Failed to load locale:', error);
}
}
private async loadLocaleData(localeKey: string): Promise<FullLocaleData> {
// Dynamic locale loading
switch (localeKey) {
case 'zh_CN':
return (await import('@delon/theme/locale/languages/zh-CN')).default;
case 'zh_TW':
return (await import('@delon/theme/locale/languages/zh-TW')).default;
case 'ja_JP':
return (await import('@delon/theme/locale/languages/ja-JP')).default;
case 'ko_KR':
return (await import('@delon/theme/locale/languages/ko-KR')).default;
case 'fr_FR':
return (await import('@delon/theme/locale/languages/fr-FR')).default;
case 'es_ES':
return (await import('@delon/theme/locale/languages/es-ES')).default;
default:
return (await import('@delon/theme/locale/languages/en-US')).default;
}
}
private updateCurrentLocaleName(locale: FullLocaleData) {
// Update UI based on locale data
document.documentElement.lang = locale.abbr || 'en';
}
getComponentText(component: keyof FullLocaleData, key: string): string {
const componentData = this.localeService.getData(component);
return componentData[key] || key;
}
}Complete type definitions for locale data structures covering all components.
/**
* Complete locale data structure
* Contains all component-specific locale data
*/
interface FullLocaleData {
abbr: string;
exception: ExceptionLocaleData;
noticeIcon: NoticeIconLocaleData;
reuseTab: ReuseTabLocaleData;
tagSelect: TagSelectLocaleData;
miniProgress: MiniProgressLocaleData;
st: STLocaleData;
sf: SFLocaleData;
onboarding: OnboardingLocaleData;
}
/**
* Exception page locale data
* Error page messages and actions
*/
interface ExceptionLocaleData {
403: string;
404: string;
500: string;
backToHome: string;
}
/**
* Notice icon component locale data
* Notification and message texts
*/
interface NoticeIconLocaleData {
emptyText: string;
clearText: string;
}
/**
* Reuse tab component locale data
* Tab management texts
*/
interface ReuseTabLocaleData {
close: string;
closeOther: string;
closeRight: string;
refresh: string;
}
/**
* Tag select component locale data
* Tag selection interface texts
*/
interface TagSelectLocaleData {
expand: string;
collapse: string;
}
/**
* Mini progress component locale data
* Progress indicator texts
*/
interface MiniProgressLocaleData {
target: string;
total: string;
}
/**
* Simple table component locale data
* Table interface and interaction texts
*/
interface STLocaleData {
total: string;
filterTitle: string;
filterConfirm: string;
filterReset: string;
}
/**
* Schema form component locale data
* Form validation and interaction texts
*/
interface SFLocaleData {
submit: string;
reset: string;
search: string;
edit: string;
addText: string;
removeText: string;
checkAllText: string;
error: {
'false schema': string;
$ref: string;
additionalItems: string;
additionalProperties: string;
anyOf: string;
dependencies: string;
enum: string;
format: string;
type: string;
required: string;
maxLength: string;
minLength: string;
minimum: string;
formatMinimum: string;
maximum: string;
formatMaximum: string;
maxItems: string;
minItems: string;
uniqueItems: string;
multipleOf: string;
not: string;
oneOf: string;
pattern: string;
switch: string;
const: string;
contains: string;
patternRequired: string;
};
}
/**
* Onboarding component locale data
* Tour and guidance texts
*/
interface OnboardingLocaleData {
skip: string;
prev: string;
next: string;
done: string;
}Usage Examples:
import { FullLocaleData, STLocaleData, SFLocaleData } from "@delon/theme";
// Creating custom locale data
const customEnglishLocale: FullLocaleData = {
abbr: 'en',
exception: {
403: 'Access Denied',
404: 'Page Not Found',
500: 'Server Error',
backToHome: 'Back to Home'
},
noticeIcon: {
emptyText: 'No notifications',
clearText: 'Clear all'
},
reuseTab: {
close: 'Close',
closeOther: 'Close Others',
closeRight: 'Close Right',
refresh: 'Refresh'
},
tagSelect: {
expand: 'Show More',
collapse: 'Show Less'
},
miniProgress: {
target: 'Target',
total: 'Total'
},
st: {
total: '{{range[0]}}-{{range[1]}} of {{total}} items',
filterTitle: 'Filter',
filterConfirm: 'OK',
filterReset: 'Reset'
},
sf: {
submit: 'Submit',
reset: 'Reset',
search: 'Search',
edit: 'Edit',
addText: 'Add',
removeText: 'Remove',
checkAllText: 'Check All',
error: {
'false schema': 'Invalid schema',
$ref: 'Reference error',
additionalItems: 'Additional items not allowed',
additionalProperties: 'Additional properties not allowed',
anyOf: 'Does not match any schema',
dependencies: 'Dependency requirements not met',
enum: 'Value not in allowed list',
format: 'Invalid format',
type: 'Invalid type',
required: 'This field is required',
maxLength: 'Text too long',
minLength: 'Text too short',
minimum: 'Value too small',
formatMinimum: 'Value below minimum',
maximum: 'Value too large',
formatMaximum: 'Value above maximum',
maxItems: 'Too many items',
minItems: 'Too few items',
uniqueItems: 'Items must be unique',
multipleOf: 'Must be multiple of {{multipleOf}}',
not: 'Does not match schema',
oneOf: 'Matches multiple schemas',
pattern: 'Does not match pattern',
switch: 'Switch validation failed',
const: 'Must be constant value',
contains: 'Must contain specific item',
patternRequired: 'Required pattern not found'
}
},
onboarding: {
skip: 'Skip',
prev: 'Previous',
next: 'Next',
done: 'Done'
}
};
// Partial locale updates
const customTableLocale: Partial<STLocaleData> = {
filterTitle: 'Advanced Filter',
filterConfirm: 'Apply Filter',
filterReset: 'Clear Filter'
};Injection token and provider for locale data dependency injection.
/**
* Injection token for locale data
* Use for providing and injecting locale configuration
*/
const DELON_LOCALE: InjectionToken<FullLocaleData>;
/**
* Default locale service provider
* Configures DelonLocaleService with factory function
*/
const DELON_LOCALE_SERVICE_PROVIDER: Provider;Usage Examples:
import { NgModule, inject } from "@angular/core";
import { DELON_LOCALE, DELON_LOCALE_SERVICE_PROVIDER } from "@delon/theme";
import enUS from "@delon/theme/locale/languages/en-US";
import zhCN from "@delon/theme/locale/languages/zh-CN";
// Provide specific locale
@NgModule({
providers: [
{ provide: DELON_LOCALE, useValue: enUS },
DELON_LOCALE_SERVICE_PROVIDER
]
})
export class AppModule {}
// Dynamic locale provider
export function createLocaleProvider(): FullLocaleData {
const browserLang = navigator.language;
switch (browserLang.toLowerCase()) {
case 'zh-cn':
case 'zh':
return zhCN;
case 'en-us':
case 'en':
default:
return enUS;
}
}
const DYNAMIC_LOCALE_PROVIDER: Provider = {
provide: DELON_LOCALE,
useFactory: createLocaleProvider
};
// Component injection
@Component({})
export class LocaleAwareComponent {
private localeData = inject(DELON_LOCALE);
constructor() {
console.log('Current locale:', this.localeData.abbr);
console.log('Exception 404 text:', this.localeData.exception[404]);
}
}
// Custom locale service
@Injectable()
export class CustomLocaleService extends DelonLocaleService {
constructor(@Inject(DELON_LOCALE) defaultLocale: FullLocaleData) {
super();
this.setLocale(defaultLocale);
}
loadLocaleAsync(localeKey: string): Promise<void> {
return import(`@delon/theme/locale/languages/${localeKey}`)
.then(module => {
this.setLocale(module.default);
});
}
}Available built-in locale configurations for international applications.
/**
* Built-in locale data imports
* Available languages with complete translations
*/
// English (US)
import en_US from "@delon/theme/locale/languages/en-US";
// Chinese
import zh_CN from "@delon/theme/locale/languages/zh-CN";
import zh_TW from "@delon/theme/locale/languages/zh-TW";
// Asian languages
import ja_JP from "@delon/theme/locale/languages/ja-JP";
import ko_KR from "@delon/theme/locale/languages/ko-KR";
import vi_VI from "@delon/theme/locale/languages/vi-VI";
// European languages
import fr_FR from "@delon/theme/locale/languages/fr-FR";
import es_ES from "@delon/theme/locale/languages/es-ES";
import it_IT from "@delon/theme/locale/languages/it-IT";
import de_DE from "@delon/theme/locale/languages/de-DE";
import pl_PL from "@delon/theme/locale/languages/pl-PL";
import el_GR from "@delon/theme/locale/languages/el-GR";
import tr_TR from "@delon/theme/locale/languages/tr-TR";
import hr_HR from "@delon/theme/locale/languages/hr-HR";
import sl_SI from "@delon/theme/locale/languages/sl-SI";
// Middle Eastern
import ar_SA from "@delon/theme/locale/languages/ar-SA";Usage Examples:
import { Component } from "@angular/core";
import { DelonLocaleService } from "@delon/theme";
// Multi-language application
@Component({
selector: "language-selector",
template: `
<select (change)="changeLanguage($event)">
<option value="en_US">English</option>
<option value="zh_CN">简体中文</option>
<option value="zh_TW">繁體中文</option>
<option value="ja_JP">日本語</option>
<option value="ko_KR">한국어</option>
<option value="fr_FR">Français</option>
<option value="es_ES">Español</option>
<option value="de_DE">Deutsch</option>
<option value="it_IT">Italiano</option>
<option value="ar_SA">العربية</option>
</select>
`
})
export class LanguageSelectorComponent {
constructor(private localeService: DelonLocaleService) {}
async changeLanguage(event: Event) {
const langCode = (event.target as HTMLSelectElement).value;
try {
// Dynamic import based on selection
const localeModule = await import(`@delon/theme/locale/languages/${langCode}`);
this.localeService.setLocale(localeModule.default);
// Update document language
document.documentElement.lang = langCode.replace('_', '-');
// Update text direction for RTL languages
if (langCode === 'ar_SA') {
document.documentElement.dir = 'rtl';
} else {
document.documentElement.dir = 'ltr';
}
} catch (error) {
console.error('Failed to load locale:', error);
}
}
}
// Locale detection utility
export class LocaleDetectionService {
private static readonly LOCALE_MAPPING: Record<string, string> = {
'en': 'en_US',
'en-US': 'en_US',
'zh': 'zh_CN',
'zh-CN': 'zh_CN',
'zh-TW': 'zh_TW',
'zh-HK': 'zh_TW',
'ja': 'ja_JP',
'ja-JP': 'ja_JP',
'ko': 'ko_KR',
'ko-KR': 'ko_KR',
'fr': 'fr_FR',
'fr-FR': 'fr_FR',
'es': 'es_ES',
'es-ES': 'es_ES',
'de': 'de_DE',
'de-DE': 'de_DE',
'it': 'it_IT',
'it-IT': 'it_IT',
'ar': 'ar_SA',
'ar-SA': 'ar_SA'
};
static detectBrowserLocale(): string {
const browserLang = navigator.language || navigator.languages[0];
return this.LOCALE_MAPPING[browserLang] || 'en_US';
}
static async loadDetectedLocale(): Promise<FullLocaleData> {
const localeKey = this.detectBrowserLocale();
const module = await import(`@delon/theme/locale/languages/${localeKey}`);
return module.default;
}
}