Angular Common provides comprehensive internationalization (i18n) support including locale data management, number and date formatting functions, localization services, and utilities for building multilingual applications.
Functions for registering and accessing locale-specific data.
/**
* Register locale data for use in Angular i18n
* Required for using non-English locales with Angular pipes and formatting
*/
export function registerLocaleData(data: any, localeId?: string | any, extraData?: any): void;
/**
* Get the locale ID from locale data
*/
export function getLocaleId(locale: string): string;Usage Examples:
import { registerLocaleData } from '@angular/common';
import localeEs from '@angular/common/locales/es';
import localeEsExtra from '@angular/common/locales/extra/es';
import localeFr from '@angular/common/locales/fr';
// Register Spanish locale
registerLocaleData(localeEs, 'es', localeEsExtra);
// Register French locale
registerLocaleData(localeFr, 'fr');
@Component({})
export class I18nSetupComponent {
constructor() {
// Get locale ID
console.log('Current locale ID:', getLocaleId('en-US')); // 'en-US'
}
}Functions to retrieve date and time formatting information for specific locales.
/**
* Get localized day names (Sunday, Monday, etc.)
*/
export function getLocaleDayNames(locale: string, formStyle: FormStyle, width: TranslationWidth): string[];
/**
* Get localized month names (January, February, etc.)
*/
export function getLocaleMonthNames(locale: string, formStyle: FormStyle, width: TranslationWidth): string[];
/**
* Get localized era names (BC, AD, etc.)
*/
export function getLocaleEraNames(locale: string, width: TranslationWidth): string[];
/**
* Get localized day periods (AM, PM, etc.)
*/
export function getLocaleDayPeriods(locale: string, formStyle: FormStyle, width: TranslationWidth): [string, string];
/**
* Get extra day period rules for locale
*/
export function getLocaleExtraDayPeriodRules(locale: string): (Time | [Time, Time])[];
/**
* Get extra day periods for locale (midnight, noon, etc.)
*/
export function getLocaleExtraDayPeriods(locale: string, formStyle: FormStyle, width: TranslationWidth): string[];
/**
* Get date format pattern for locale
*/
export function getLocaleDateFormat(locale: string, width: FormatWidth): string;
/**
* Get time format pattern for locale
*/
export function getLocaleTimeFormat(locale: string, width: FormatWidth): string;
/**
* Get combined date-time format pattern for locale
*/
export function getLocaleDateTimeFormat(locale: string, width: FormatWidth): string;
/**
* Get first day of week for locale (0 = Sunday, 1 = Monday, etc.)
*/
export function getLocaleFirstDayOfWeek(locale: string): WeekDay;
/**
* Get weekend range for locale [start, end]
*/
export function getLocaleWeekEndRange(locale: string): [WeekDay, WeekDay];
/**
* Get text direction for locale ('ltr' or 'rtl')
*/
export function getLocaleDirection(locale: string): 'ltr' | 'rtl';Usage Examples:
@Injectable()
export class DateLocalizationService {
// Get localized date components
getLocalizedDateInfo(locale: string) {
return {
dayNames: {
wide: getLocaleDayNames(locale, FormStyle.Format, TranslationWidth.Wide),
abbreviated: getLocaleDayNames(locale, FormStyle.Format, TranslationWidth.Abbreviated),
narrow: getLocaleDayNames(locale, FormStyle.Format, TranslationWidth.Narrow)
},
monthNames: {
wide: getLocaleMonthNames(locale, FormStyle.Format, TranslationWidth.Wide),
abbreviated: getLocaleMonthNames(locale, FormStyle.Format, TranslationWidth.Abbreviated),
narrow: getLocaleMonthNames(locale, FormStyle.Format, TranslationWidth.Narrow)
},
dayPeriods: getLocaleDayPeriods(locale, FormStyle.Format, TranslationWidth.Wide),
eraNames: getLocaleEraNames(locale, TranslationWidth.Wide)
};
}
// Get format patterns
getDateFormats(locale: string) {
return {
short: getLocaleDateFormat(locale, FormatWidth.Short),
medium: getLocaleDateFormat(locale, FormatWidth.Medium),
long: getLocaleDateFormat(locale, FormatWidth.Long),
full: getLocaleDateFormat(locale, FormatWidth.Full)
};
}
getTimeFormats(locale: string) {
return {
short: getLocaleTimeFormat(locale, FormatWidth.Short),
medium: getLocaleTimeFormat(locale, FormatWidth.Medium),
long: getLocaleTimeFormat(locale, FormatWidth.Long),
full: getLocaleTimeFormat(locale, FormatWidth.Full)
};
}
getDateTimeFormats(locale: string) {
return {
short: getLocaleDateTimeFormat(locale, FormatWidth.Short),
medium: getLocaleDateTimeFormat(locale, FormatWidth.Medium),
long: getLocaleDateTimeFormat(locale, FormatWidth.Long),
full: getLocaleDateTimeFormat(locale, FormatWidth.Full)
};
}
// Calendar information
getCalendarInfo(locale: string) {
return {
firstDayOfWeek: getLocaleFirstDayOfWeek(locale),
weekendRange: getLocaleWeekEndRange(locale),
direction: getLocaleDirection(locale)
};
}
}
@Component({
template: `
<div>
<h3>{{ locale }} Date Information</h3>
<p>Direction: {{ calendarInfo.direction }}</p>
<p>First day of week: {{ getDayName(calendarInfo.firstDayOfWeek) }}</p>
<p>Weekend: {{ getWeekendInfo() }}</p>
<h4>Day Names</h4>
<ul>
<li *ngFor="let day of dateInfo.dayNames.wide; let i = index">
{{ i }}: {{ day }}
</li>
</ul>
<h4>Month Names</h4>
<ul>
<li *ngFor="let month of dateInfo.monthNames.abbreviated; let i = index">
{{ i + 1 }}: {{ month }}
</li>
</ul>
</div>
`
})
export class LocaleInfoComponent {
locale = 'en-US';
dateInfo: any;
calendarInfo: any;
constructor(private dateLocalization: DateLocalizationService) {
this.loadLocaleInfo();
}
loadLocaleInfo() {
this.dateInfo = this.dateLocalization.getLocalizedDateInfo(this.locale);
this.calendarInfo = this.dateLocalization.getCalendarInfo(this.locale);
}
getDayName(dayIndex: WeekDay): string {
return this.dateInfo.dayNames.wide[dayIndex];
}
getWeekendInfo(): string {
const [start, end] = this.calendarInfo.weekendRange;
return `${this.getDayName(start)} - ${this.getDayName(end)}`;
}
changeLocale(newLocale: string) {
this.locale = newLocale;
this.loadLocaleInfo();
}
}Functions to retrieve number and currency formatting information.
/**
* Get localized number symbols (decimal separator, thousands separator, etc.)
*/
export function getLocaleNumberSymbol(locale: string, symbol: NumberSymbol): string;
/**
* Get number format pattern for locale
*/
export function getLocaleNumberFormat(locale: string, type: NumberFormatStyle): string;
/**
* Get currency code for locale
*/
export function getLocaleCurrencyCode(locale: string): string | null;
/**
* Get currency name for locale and currency code
*/
export function getLocaleCurrencyName(locale: string, currency: string): string | null;
/**
* Get currency symbol for locale and currency code
*/
export function getLocaleCurrencySymbol(locale: string, currency: string): string | null;
/**
* Get number of digits after decimal for currency
*/
export function getNumberOfCurrencyDigits(code: string): number;
/**
* Get currency symbol by currency code
*/
export function getCurrencySymbol(code: string, format: 'wide' | 'narrow', locale?: string): string;Usage Examples:
@Injectable()
export class NumberLocalizationService {
// Get number formatting info
getNumberFormatInfo(locale: string) {
return {
decimal: getLocaleNumberSymbol(locale, NumberSymbol.Decimal),
group: getLocaleNumberSymbol(locale, NumberSymbol.Group),
list: getLocaleNumberSymbol(locale, NumberSymbol.List),
percentSign: getLocaleNumberSymbol(locale, NumberSymbol.PercentSign),
plusSign: getLocaleNumberSymbol(locale, NumberSymbol.PlusSign),
minusSign: getLocaleNumberSymbol(locale, NumberSymbol.MinusSign),
exponential: getLocaleNumberSymbol(locale, NumberSymbol.Exponential),
infinity: getLocaleNumberSymbol(locale, NumberSymbol.Infinity),
nan: getLocaleNumberSymbol(locale, NumberSymbol.NaN)
};
}
// Get number format patterns
getNumberFormats(locale: string) {
return {
decimal: getLocaleNumberFormat(locale, NumberFormatStyle.Decimal),
percent: getLocaleNumberFormat(locale, NumberFormatStyle.Percent),
currency: getLocaleNumberFormat(locale, NumberFormatStyle.Currency),
scientific: getLocaleNumberFormat(locale, NumberFormatStyle.Scientific)
};
}
// Get currency information
getCurrencyInfo(locale: string) {
const currencyCode = getLocaleCurrencyCode(locale);
if (!currencyCode) return null;
return {
code: currencyCode,
name: getLocaleCurrencyName(locale, currencyCode),
symbol: getLocaleCurrencySymbol(locale, currencyCode),
digits: getNumberOfCurrencyDigits(currencyCode),
wideSymbol: getCurrencySymbol(currencyCode, 'wide', locale),
narrowSymbol: getCurrencySymbol(currencyCode, 'narrow', locale)
};
}
// Format number with locale-specific symbols
formatNumberWithLocaleSymbols(value: number, locale: string): string {
const symbols = this.getNumberFormatInfo(locale);
const formatted = value.toLocaleString(locale);
// Example of manual formatting (usually use Angular pipes instead)
return formatted;
}
// Get all currency symbols for common currencies
getAllCurrencySymbols(locale: string) {
const currencies = ['USD', 'EUR', 'GBP', 'JPY', 'CNY', 'INR'];
return currencies.reduce((acc, curr) => {
acc[curr] = {
wide: getCurrencySymbol(curr, 'wide', locale),
narrow: getCurrencySymbol(curr, 'narrow', locale),
digits: getNumberOfCurrencyDigits(curr)
};
return acc;
}, {} as any);
}
}
@Component({
template: `
<div>
<h3>{{ locale }} Number Formatting</h3>
<h4>Number Symbols</h4>
<ul>
<li>Decimal: "{{ numberSymbols.decimal }}"</li>
<li>Group: "{{ numberSymbols.group }}"</li>
<li>Percent: "{{ numberSymbols.percentSign }}"</li>
<li>Plus: "{{ numberSymbols.plusSign }}"</li>
<li>Minus: "{{ numberSymbols.minusSign }}"</li>
</ul>
<h4>Currency Information</h4>
<div *ngIf="currencyInfo">
<p>Code: {{ currencyInfo.code }}</p>
<p>Name: {{ currencyInfo.name }}</p>
<p>Symbol: {{ currencyInfo.symbol }}</p>
<p>Digits: {{ currencyInfo.digits }}</p>
<p>Wide Symbol: {{ currencyInfo.wideSymbol }}</p>
<p>Narrow Symbol: {{ currencyInfo.narrowSymbol }}</p>
</div>
<h4>All Currencies</h4>
<div *ngFor="let currency of currencyEntries">
<strong>{{ currency.key }}:</strong>
{{ currency.value.wide }} / {{ currency.value.narrow }}
({{ currency.value.digits }} digits)
</div>
</div>
`
})
export class NumberInfoComponent {
locale = 'en-US';
numberSymbols: any;
currencyInfo: any;
currencyEntries: any[];
constructor(private numberLocalization: NumberLocalizationService) {
this.loadNumberInfo();
}
loadNumberInfo() {
this.numberSymbols = this.numberLocalization.getNumberFormatInfo(this.locale);
this.currencyInfo = this.numberLocalization.getCurrencyInfo(this.locale);
const allCurrencies = this.numberLocalization.getAllCurrencySymbols(this.locale);
this.currencyEntries = Object.entries(allCurrencies).map(([key, value]) => ({ key, value }));
}
changeLocale(newLocale: string) {
this.locale = newLocale;
this.loadNumberInfo();
}
}Functions for handling pluralization based on locale rules.
/**
* Get plural category for a number in given locale
* Returns 'zero', 'one', 'two', 'few', 'many', or 'other'
*/
export function getLocalePluralCase(locale: string): (value: number) => string;Usage Examples:
@Injectable()
export class PluralizationService {
// Get plural function for locale
getPluralFunction(locale: string) {
return getLocalePluralCase(locale);
}
// Get plural category for number
getPluralCategory(value: number, locale: string): string {
const pluralFn = this.getPluralFunction(locale);
return pluralFn(value);
}
// Create plural message mappings
createPluralMapping(locale: string) {
const pluralFn = this.getPluralFunction(locale);
// Test different numbers to understand the pattern
const testNumbers = [0, 1, 2, 3, 5, 10, 21, 101];
const results = testNumbers.map(num => ({
number: num,
category: pluralFn(num)
}));
console.log(`Plural categories for ${locale}:`, results);
return results;
}
// Message selection based on plural rules
selectPluralMessage(count: number, messages: { [key: string]: string }, locale: string): string {
const category = this.getPluralCategory(count, locale);
// Try exact match first (=0, =1, etc.)
const exactKey = `=${count}`;
if (messages[exactKey]) {
return messages[exactKey].replace('#', count.toString());
}
// Use plural category
if (messages[category]) {
return messages[category].replace('#', count.toString());
}
// Fallback to 'other'
return messages['other']?.replace('#', count.toString()) || count.toString();
}
}
@Component({
template: `
<div>
<h3>Pluralization Examples</h3>
<div>
<label>Count: </label>
<input type="number" [(ngModel)]="count" min="0">
</div>
<div>
<label>Locale: </label>
<select [(ngModel)]="locale" (change)="updatePluralization()">
<option value="en">English</option>
<option value="es">Spanish</option>
<option value="fr">French</option>
<option value="ru">Russian</option>
<option value="ar">Arabic</option>
</select>
</div>
<div>
<p>Plural category: {{ currentCategory }}</p>
<p>Message: {{ currentMessage }}</p>
</div>
<h4>Message Examples</h4>
<ul>
<li>Items: {{ getItemMessage() }}</li>
<li>Files: {{ getFileMessage() }}</li>
<li>Users: {{ getUserMessage() }}</li>
</ul>
<h4>Plural Categories for {{ locale }}</h4>
<ul>
<li *ngFor="let result of pluralResults">
{{ result.number }}: {{ result.category }}
</li>
</ul>
</div>
`
})
export class PluralizationComponent {
count = 1;
locale = 'en';
currentCategory = '';
currentMessage = '';
pluralResults: any[] = [];
private itemMessages = {
'=0': 'No items',
'=1': 'One item',
'other': '# items'
};
private fileMessages = {
'=0': 'No files to download',
'=1': 'One file to download',
'other': '# files to download'
};
private userMessages = {
'=0': 'No users online',
'=1': 'One user online',
'other': '# users online'
};
constructor(private pluralizationService: PluralizationService) {
this.updatePluralization();
}
updatePluralization() {
this.currentCategory = this.pluralizationService.getPluralCategory(this.count, this.locale);
this.currentMessage = this.pluralizationService.selectPluralMessage(
this.count,
this.itemMessages,
this.locale
);
this.pluralResults = this.pluralizationService.createPluralMapping(this.locale);
}
getItemMessage(): string {
return this.pluralizationService.selectPluralMessage(this.count, this.itemMessages, this.locale);
}
getFileMessage(): string {
return this.pluralizationService.selectPluralMessage(this.count, this.fileMessages, this.locale);
}
getUserMessage(): string {
return this.pluralizationService.selectPluralMessage(this.count, this.userMessages, this.locale);
}
}Functions for formatting dates and numbers outside of pipes.
/**
* Format date according to locale rules
* Same functionality as DatePipe but as standalone function
*/
export function formatDate(value: string | number | Date, format: string, locale: string, timezone?: string): string;
/**
* Format number as currency according to locale rules
*/
export function formatCurrency(value: number, locale: string, currency: string, currencyCode?: string, digitsInfo?: string): string;
/**
* Format number according to locale rules
*/
export function formatNumber(value: number, locale: string, digitsInfo?: string): string;
/**
* Format number as percentage according to locale rules
*/
export function formatPercent(value: number, locale: string, digitsInfo?: string): string;Usage Examples:
@Injectable()
export class FormattingService {
// Date formatting
formatDateForLocale(date: Date, locale: string): any {
return {
short: formatDate(date, 'short', locale),
medium: formatDate(date, 'medium', locale),
long: formatDate(date, 'long', locale),
full: formatDate(date, 'full', locale),
custom: formatDate(date, 'MMM d, y, h:mm a', locale),
timeOnly: formatDate(date, 'HH:mm:ss', locale),
dateOnly: formatDate(date, 'yyyy-MM-dd', locale)
};
}
// Number formatting
formatNumberForLocale(value: number, locale: string): any {
return {
default: formatNumber(value, locale),
twoDigits: formatNumber(value, locale, '1.2-2'),
minThreeDigits: formatNumber(value, locale, '3.1-5'),
noDecimals: formatNumber(value, locale, '1.0-0')
};
}
// Currency formatting
formatCurrencyForLocale(value: number, locale: string): any {
const currencyCode = getLocaleCurrencyCode(locale) || 'USD';
return {
default: formatCurrency(value, locale, currencyCode),
code: formatCurrency(value, locale, currencyCode, 'code'),
symbol: formatCurrency(value, locale, currencyCode, 'symbol'),
narrow: formatCurrency(value, locale, currencyCode, 'symbol-narrow'),
twoDigits: formatCurrency(value, locale, currencyCode, 'symbol', '1.2-2'),
usd: formatCurrency(value, locale, 'USD', 'symbol'),
eur: formatCurrency(value, locale, 'EUR', 'symbol')
};
}
// Percentage formatting
formatPercentForLocale(value: number, locale: string): any {
return {
default: formatPercent(value, locale),
twoDigits: formatPercent(value, locale, '1.2-2'),
noDecimals: formatPercent(value, locale, '1.0-0'),
threeDigits: formatPercent(value, locale, '1.3-3')
};
}
// Multi-locale comparison
compareFormats(value: number, locales: string[]) {
return locales.map(locale => ({
locale,
number: formatNumber(value, locale),
currency: formatCurrency(value, locale, getLocaleCurrencyCode(locale) || 'USD'),
percent: formatPercent(value / 100, locale) // Convert to percentage
}));
}
// Date comparison across locales
compareDateFormats(date: Date, locales: string[]) {
return locales.map(locale => ({
locale,
short: formatDate(date, 'short', locale),
medium: formatDate(date, 'medium', locale),
full: formatDate(date, 'full', locale)
}));
}
}
@Component({
template: `
<div>
<h3>Formatting Examples</h3>
<div>
<label>Value: </label>
<input type="number" [(ngModel)]="testValue" step="0.01">
</div>
<div>
<label>Locale: </label>
<select [(ngModel)]="selectedLocale">
<option value="en-US">English (US)</option>
<option value="de-DE">German</option>
<option value="fr-FR">French</option>
<option value="ja-JP">Japanese</option>
<option value="ar-EG">Arabic</option>
</select>
</div>
<h4>Date Formats</h4>
<ul>
<li *ngFor="let format of dateFormats | keyvalue">
{{ format.key }}: {{ format.value }}
</li>
</ul>
<h4>Number Formats</h4>
<ul>
<li *ngFor="let format of numberFormats | keyvalue">
{{ format.key }}: {{ format.value }}
</li>
</ul>
<h4>Currency Formats</h4>
<ul>
<li *ngFor="let format of currencyFormats | keyvalue">
{{ format.key }}: {{ format.value }}
</li>
</ul>
<h4>Percentage Formats</h4>
<ul>
<li *ngFor="let format of percentFormats | keyvalue">
{{ format.key }}: {{ format.value }}
</li>
</ul>
<h4>Multi-Locale Comparison</h4>
<table>
<thead>
<tr>
<th>Locale</th>
<th>Number</th>
<th>Currency</th>
<th>Percent</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let comparison of multiLocaleComparison">
<td>{{ comparison.locale }}</td>
<td>{{ comparison.number }}</td>
<td>{{ comparison.currency }}</td>
<td>{{ comparison.percent }}</td>
</tr>
</tbody>
</table>
</div>
`
})
export class FormattingExampleComponent {
testValue = 1234.567;
selectedLocale = 'en-US';
dateFormats: any = {};
numberFormats: any = {};
currencyFormats: any = {};
percentFormats: any = {};
multiLocaleComparison: any[] = [];
private testDate = new Date();
private compareLocales = ['en-US', 'de-DE', 'fr-FR', 'ja-JP'];
constructor(private formattingService: FormattingService) {
this.updateFormats();
}
ngOnChanges() {
this.updateFormats();
}
updateFormats() {
this.dateFormats = this.formattingService.formatDateForLocale(this.testDate, this.selectedLocale);
this.numberFormats = this.formattingService.formatNumberForLocale(this.testValue, this.selectedLocale);
this.currencyFormats = this.formattingService.formatCurrencyForLocale(this.testValue, this.selectedLocale);
this.percentFormats = this.formattingService.formatPercentForLocale(this.testValue / 100, this.selectedLocale);
this.multiLocaleComparison = this.formattingService.compareFormats(this.testValue, this.compareLocales);
}
}Services for handling localization logic.
/**
* Abstract base class for localization services
* Provides interface for plural category resolution
*/
export abstract class NgLocalization {
abstract getPluralCategory(value: any, locale?: string): string;
}
/**
* Default implementation using browser locale data
*/
export class NgLocaleLocalization extends NgLocalization {
constructor(@Inject(LOCALE_ID) protected locale: string);
getPluralCategory(value: any, locale?: string): string;
}Usage Examples:
// Custom localization service
@Injectable()
export class CustomLocalizationService extends NgLocalization {
getPluralCategory(value: any, locale?: string): string {
// Custom pluralization logic
const num = Number(value);
if (locale?.startsWith('en')) {
return num === 1 ? 'one' : 'other';
}
// Add more locale-specific rules
return 'other';
}
// Additional custom methods
getCustomMessage(key: string, locale: string): string {
// Custom message resolution logic
return `Message for ${key} in ${locale}`;
}
}
// Using localization service
@Component({
providers: [
{ provide: NgLocalization, useClass: CustomLocalizationService }
]
})
export class LocalizedComponent {
constructor(private localization: NgLocalization) {}
getLocalizedMessage(count: number): string {
const category = this.localization.getPluralCategory(count);
const messages = {
'one': 'You have one item',
'other': `You have ${count} items`
};
return messages[category] || messages['other'];
}
}// Form and format styles
export enum FormStyle {
Format = 0,
Standalone = 1
}
export enum FormatWidth {
Short = 0,
Medium = 1,
Long = 2,
Full = 3
}
export enum TranslationWidth {
Narrow = 0,
Abbreviated = 1,
Wide = 2,
Short = 3
}
// Number formatting
export enum NumberFormatStyle {
Decimal = 0,
Percent = 1,
Currency = 2,
Scientific = 3
}
export enum NumberSymbol {
Decimal = 0,
Group = 1,
List = 2,
PercentSign = 3,
PlusSign = 4,
MinusSign = 5,
Exponential = 6,
SuperscriptingExponent = 7,
PerMille = 8,
Infinity = 9,
NaN = 10,
TimeSeparator = 11,
CurrencyDecimal = 12,
CurrencyGroup = 13
}
// Plural categories
export enum Plural {
Zero = 0,
One = 1,
Two = 2,
Few = 3,
Many = 4,
Other = 5
}
// Time and calendar
export enum WeekDay {
Sunday = 0,
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Thursday = 4,
Friday = 5,
Saturday = 6
}
export enum Time {
AM = 0,
PM = 1
}