@angular/common
Version:
Angular - commonly needed directives and services
1,163 lines (1,155 loc) • 209 kB
JavaScript
/**
* @license Angular v20.0.0
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
import * as i0 from '@angular/core';
import { Optional, Inject, Injectable, ɵgetLocalePluralCase as _getLocalePluralCase, ɵfindLocaleData as _findLocaleData, ɵLocaleDataIndex as _LocaleDataIndex, ɵgetLocaleCurrencyCode as _getLocaleCurrencyCode, ɵRuntimeError as _RuntimeError, ɵformatRuntimeError as _formatRuntimeError, LOCALE_ID, ɵstringify as _stringify, Input, Directive, createNgModule, NgModuleRef, Host, Attribute, RendererStyleFlags2, inject, ɵINTERNAL_APPLICATION_ERROR_HANDLER as _INTERNAL_APPLICATION_ERROR_HANDLER, ɵisPromise as _isPromise, ɵisSubscribable as _isSubscribable, untracked, Pipe, InjectionToken, DEFAULT_CURRENCY_CODE, NgModule } from '@angular/core';
import { LocationStrategy, joinWithSlash, normalizeQueryParams, PlatformLocation, APP_BASE_HREF } from './location-DTVjZRwU.mjs';
/**
* @description
* A {@link LocationStrategy} used to configure the {@link Location} service to
* represent its state in the
* [hash fragment](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax)
* of the browser's URL.
*
* For instance, if you call `location.go('/foo')`, the browser's URL will become
* `example.com#/foo`.
*
* @usageNotes
*
* ### Example
*
* {@example common/location/ts/hash_location_component.ts region='LocationComponent'}
*
* @publicApi
*/
class HashLocationStrategy extends LocationStrategy {
_platformLocation;
_baseHref = '';
_removeListenerFns = [];
constructor(_platformLocation, _baseHref) {
super();
this._platformLocation = _platformLocation;
if (_baseHref != null) {
this._baseHref = _baseHref;
}
}
/** @docs-private */
ngOnDestroy() {
while (this._removeListenerFns.length) {
this._removeListenerFns.pop()();
}
}
onPopState(fn) {
this._removeListenerFns.push(this._platformLocation.onPopState(fn), this._platformLocation.onHashChange(fn));
}
getBaseHref() {
return this._baseHref;
}
path(includeHash = false) {
// the hash value is always prefixed with a `#`
// and if it is empty then it will stay empty
const path = this._platformLocation.hash ?? '#';
return path.length > 0 ? path.substring(1) : path;
}
prepareExternalUrl(internal) {
const url = joinWithSlash(this._baseHref, internal);
return url.length > 0 ? '#' + url : url;
}
pushState(state, title, path, queryParams) {
const url = this.prepareExternalUrl(path + normalizeQueryParams(queryParams)) ||
this._platformLocation.pathname;
this._platformLocation.pushState(state, title, url);
}
replaceState(state, title, path, queryParams) {
const url = this.prepareExternalUrl(path + normalizeQueryParams(queryParams)) ||
this._platformLocation.pathname;
this._platformLocation.replaceState(state, title, url);
}
forward() {
this._platformLocation.forward();
}
back() {
this._platformLocation.back();
}
getState() {
return this._platformLocation.getState();
}
historyGo(relativePosition = 0) {
this._platformLocation.historyGo?.(relativePosition);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: HashLocationStrategy, deps: [{ token: PlatformLocation }, { token: APP_BASE_HREF, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: HashLocationStrategy });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.0", ngImport: i0, type: HashLocationStrategy, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: PlatformLocation }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [APP_BASE_HREF]
}] }] });
/** @internal */
const CURRENCIES_EN = { "ADP": [undefined, undefined, 0], "AFN": [undefined, "؋", 0], "ALL": [undefined, undefined, 0], "AMD": [undefined, "֏", 2], "AOA": [undefined, "Kz"], "ARS": [undefined, "$"], "AUD": ["A$", "$"], "AZN": [undefined, "₼"], "BAM": [undefined, "KM"], "BBD": [undefined, "$"], "BDT": [undefined, "৳"], "BHD": [undefined, undefined, 3], "BIF": [undefined, undefined, 0], "BMD": [undefined, "$"], "BND": [undefined, "$"], "BOB": [undefined, "Bs"], "BRL": ["R$"], "BSD": [undefined, "$"], "BWP": [undefined, "P"], "BYN": [undefined, undefined, 2], "BYR": [undefined, undefined, 0], "BZD": [undefined, "$"], "CAD": ["CA$", "$", 2], "CHF": [undefined, undefined, 2], "CLF": [undefined, undefined, 4], "CLP": [undefined, "$", 0], "CNY": ["CN¥", "¥"], "COP": [undefined, "$", 2], "CRC": [undefined, "₡", 2], "CUC": [undefined, "$"], "CUP": [undefined, "$"], "CZK": [undefined, "Kč", 2], "DJF": [undefined, undefined, 0], "DKK": [undefined, "kr", 2], "DOP": [undefined, "$"], "EGP": [undefined, "E£"], "ESP": [undefined, "₧", 0], "EUR": ["€"], "FJD": [undefined, "$"], "FKP": [undefined, "£"], "GBP": ["£"], "GEL": [undefined, "₾"], "GHS": [undefined, "GH₵"], "GIP": [undefined, "£"], "GNF": [undefined, "FG", 0], "GTQ": [undefined, "Q"], "GYD": [undefined, "$", 2], "HKD": ["HK$", "$"], "HNL": [undefined, "L"], "HRK": [undefined, "kn"], "HUF": [undefined, "Ft", 2], "IDR": [undefined, "Rp", 2], "ILS": ["₪"], "INR": ["₹"], "IQD": [undefined, undefined, 0], "IRR": [undefined, undefined, 0], "ISK": [undefined, "kr", 0], "ITL": [undefined, undefined, 0], "JMD": [undefined, "$"], "JOD": [undefined, undefined, 3], "JPY": ["¥", undefined, 0], "KHR": [undefined, "៛"], "KMF": [undefined, "CF", 0], "KPW": [undefined, "₩", 0], "KRW": ["₩", undefined, 0], "KWD": [undefined, undefined, 3], "KYD": [undefined, "$"], "KZT": [undefined, "₸"], "LAK": [undefined, "₭", 0], "LBP": [undefined, "L£", 0], "LKR": [undefined, "Rs"], "LRD": [undefined, "$"], "LTL": [undefined, "Lt"], "LUF": [undefined, undefined, 0], "LVL": [undefined, "Ls"], "LYD": [undefined, undefined, 3], "MGA": [undefined, "Ar", 0], "MGF": [undefined, undefined, 0], "MMK": [undefined, "K", 0], "MNT": [undefined, "₮", 2], "MRO": [undefined, undefined, 0], "MUR": [undefined, "Rs", 2], "MXN": ["MX$", "$"], "MYR": [undefined, "RM"], "NAD": [undefined, "$"], "NGN": [undefined, "₦"], "NIO": [undefined, "C$"], "NOK": [undefined, "kr", 2], "NPR": [undefined, "Rs"], "NZD": ["NZ$", "$"], "OMR": [undefined, undefined, 3], "PHP": ["₱"], "PKR": [undefined, "Rs", 2], "PLN": [undefined, "zł"], "PYG": [undefined, "₲", 0], "RON": [undefined, "lei"], "RSD": [undefined, undefined, 0], "RUB": [undefined, "₽"], "RWF": [undefined, "RF", 0], "SBD": [undefined, "$"], "SEK": [undefined, "kr", 2], "SGD": [undefined, "$"], "SHP": [undefined, "£"], "SLE": [undefined, undefined, 2], "SLL": [undefined, undefined, 0], "SOS": [undefined, undefined, 0], "SRD": [undefined, "$"], "SSP": [undefined, "£"], "STD": [undefined, undefined, 0], "STN": [undefined, "Db"], "SYP": [undefined, "£", 0], "THB": [undefined, "฿"], "TMM": [undefined, undefined, 0], "TND": [undefined, undefined, 3], "TOP": [undefined, "T$"], "TRL": [undefined, undefined, 0], "TRY": [undefined, "₺"], "TTD": [undefined, "$"], "TWD": ["NT$", "$", 2], "TZS": [undefined, undefined, 2], "UAH": [undefined, "₴"], "UGX": [undefined, undefined, 0], "USD": ["$"], "UYI": [undefined, undefined, 0], "UYU": [undefined, "$"], "UYW": [undefined, undefined, 4], "UZS": [undefined, undefined, 2], "VEF": [undefined, "Bs", 2], "VND": ["₫", undefined, 0], "VUV": [undefined, undefined, 0], "XAF": ["FCFA", undefined, 0], "XCD": ["EC$", "$"], "XOF": ["F CFA", undefined, 0], "XPF": ["CFPF", undefined, 0], "XXX": ["¤"], "YER": [undefined, undefined, 0], "ZAR": [undefined, "R"], "ZMK": [undefined, undefined, 0], "ZMW": [undefined, "ZK"], "ZWD": [undefined, undefined, 0] };
/**
* Format styles that can be used to represent numbers.
* @see {@link getLocaleNumberFormat}
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated `getLocaleNumberFormat` is deprecated
*/
var NumberFormatStyle;
(function (NumberFormatStyle) {
NumberFormatStyle[NumberFormatStyle["Decimal"] = 0] = "Decimal";
NumberFormatStyle[NumberFormatStyle["Percent"] = 1] = "Percent";
NumberFormatStyle[NumberFormatStyle["Currency"] = 2] = "Currency";
NumberFormatStyle[NumberFormatStyle["Scientific"] = 3] = "Scientific";
})(NumberFormatStyle || (NumberFormatStyle = {}));
/**
* Plurality cases used for translating plurals to different languages.
*
* @see {@link NgPlural}
* @see {@link NgPluralCase}
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated `getLocalePluralCase` is deprecated
*/
var Plural;
(function (Plural) {
Plural[Plural["Zero"] = 0] = "Zero";
Plural[Plural["One"] = 1] = "One";
Plural[Plural["Two"] = 2] = "Two";
Plural[Plural["Few"] = 3] = "Few";
Plural[Plural["Many"] = 4] = "Many";
Plural[Plural["Other"] = 5] = "Other";
})(Plural || (Plural = {}));
/**
* Context-dependant translation forms for strings.
* Typically the standalone version is for the nominative form of the word,
* and the format version is used for the genitive case.
* @see [CLDR website](http://cldr.unicode.org/translation/date-time-1/date-time#TOC-Standalone-vs.-Format-Styles)
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated locale data getters are deprecated
*/
var FormStyle;
(function (FormStyle) {
FormStyle[FormStyle["Format"] = 0] = "Format";
FormStyle[FormStyle["Standalone"] = 1] = "Standalone";
})(FormStyle || (FormStyle = {}));
/**
* String widths available for translations.
* The specific character widths are locale-specific.
* Examples are given for the word "Sunday" in English.
*
* @publicApi
*
* @deprecated locale data getters are deprecated
*/
var TranslationWidth;
(function (TranslationWidth) {
/** 1 character for `en-US`. For example: 'S' */
TranslationWidth[TranslationWidth["Narrow"] = 0] = "Narrow";
/** 3 characters for `en-US`. For example: 'Sun' */
TranslationWidth[TranslationWidth["Abbreviated"] = 1] = "Abbreviated";
/** Full length for `en-US`. For example: "Sunday" */
TranslationWidth[TranslationWidth["Wide"] = 2] = "Wide";
/** 2 characters for `en-US`, For example: "Su" */
TranslationWidth[TranslationWidth["Short"] = 3] = "Short";
})(TranslationWidth || (TranslationWidth = {}));
/**
* String widths available for date-time formats.
* The specific character widths are locale-specific.
* Examples are given for `en-US`.
*
* @see {@link getLocaleDateFormat}
* @see {@link getLocaleTimeFormat}
* @see {@link getLocaleDateTimeFormat}
* @see [Internationalization (i18n) Guide](guide/i18n)
* @publicApi
*
* @deprecated 18.0
* Date locale data getters are deprecated
*/
var FormatWidth;
(function (FormatWidth) {
/**
* For `en-US`, `'M/d/yy, h:mm a'`
* (Example: `6/15/15, 9:03 AM`)
*/
FormatWidth[FormatWidth["Short"] = 0] = "Short";
/**
* For `en-US`, `'MMM d, y, h:mm:ss a'`
* (Example: `Jun 15, 2015, 9:03:01 AM`)
*/
FormatWidth[FormatWidth["Medium"] = 1] = "Medium";
/**
* For `en-US`, `'MMMM d, y, h:mm:ss a z'`
* (Example: `June 15, 2015 at 9:03:01 AM GMT+1`)
*/
FormatWidth[FormatWidth["Long"] = 2] = "Long";
/**
* For `en-US`, `'EEEE, MMMM d, y, h:mm:ss a zzzz'`
* (Example: `Monday, June 15, 2015 at 9:03:01 AM GMT+01:00`)
*/
FormatWidth[FormatWidth["Full"] = 3] = "Full";
})(FormatWidth || (FormatWidth = {}));
// This needs to be an object literal, rather than an enum, because TypeScript 5.4+
// doesn't allow numeric keys and we have `Infinity` and `NaN`.
/**
* Symbols that can be used to replace placeholders in number patterns.
* Examples are based on `en-US` values.
*
* @see {@link getLocaleNumberSymbol}
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated `getLocaleNumberSymbol` is deprecated
*
* @object-literal-as-enum
*/
const NumberSymbol = {
/**
* Decimal separator.
* For `en-US`, the dot character.
* Example: 2,345`.`67
*/
Decimal: 0,
/**
* Grouping separator, typically for thousands.
* For `en-US`, the comma character.
* Example: 2`,`345.67
*/
Group: 1,
/**
* List-item separator.
* Example: "one, two, and three"
*/
List: 2,
/**
* Sign for percentage (out of 100).
* Example: 23.4%
*/
PercentSign: 3,
/**
* Sign for positive numbers.
* Example: +23
*/
PlusSign: 4,
/**
* Sign for negative numbers.
* Example: -23
*/
MinusSign: 5,
/**
* Computer notation for exponential value (n times a power of 10).
* Example: 1.2E3
*/
Exponential: 6,
/**
* Human-readable format of exponential.
* Example: 1.2x103
*/
SuperscriptingExponent: 7,
/**
* Sign for permille (out of 1000).
* Example: 23.4‰
*/
PerMille: 8,
/**
* Infinity, can be used with plus and minus.
* Example: ∞, +∞, -∞
*/
Infinity: 9,
/**
* Not a number.
* Example: NaN
*/
NaN: 10,
/**
* Symbol used between time units.
* Example: 10:52
*/
TimeSeparator: 11,
/**
* Decimal separator for currency values (fallback to `Decimal`).
* Example: $2,345.67
*/
CurrencyDecimal: 12,
/**
* Group separator for currency values (fallback to `Group`).
* Example: $2,345.67
*/
CurrencyGroup: 13,
};
/**
* The value for each day of the week, based on the `en-US` locale
*
* @publicApi
*
* @deprecated Week locale getters are deprecated
*/
var WeekDay;
(function (WeekDay) {
WeekDay[WeekDay["Sunday"] = 0] = "Sunday";
WeekDay[WeekDay["Monday"] = 1] = "Monday";
WeekDay[WeekDay["Tuesday"] = 2] = "Tuesday";
WeekDay[WeekDay["Wednesday"] = 3] = "Wednesday";
WeekDay[WeekDay["Thursday"] = 4] = "Thursday";
WeekDay[WeekDay["Friday"] = 5] = "Friday";
WeekDay[WeekDay["Saturday"] = 6] = "Saturday";
})(WeekDay || (WeekDay = {}));
/**
* Retrieves the locale ID from the currently loaded locale.
* The loaded locale could be, for example, a global one rather than a regional one.
* @param locale A locale code, such as `fr-FR`.
* @returns The locale code. For example, `fr`.
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* This function serves no purpose when relying on the `Intl` API.
*/
function getLocaleId(locale) {
return _findLocaleData(locale)[_LocaleDataIndex.LocaleId];
}
/**
* Retrieves day period strings for the given locale.
*
* @param locale A locale code for the locale format rules to use.
* @param formStyle The required grammatical form.
* @param width The required character width.
* @returns An array of localized period strings. For example, `[AM, PM]` for `en-US`.
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* Use `Intl.DateTimeFormat` for date formating instead.
*/
function getLocaleDayPeriods(locale, formStyle, width) {
const data = _findLocaleData(locale);
const amPmData = [
data[_LocaleDataIndex.DayPeriodsFormat],
data[_LocaleDataIndex.DayPeriodsStandalone],
];
const amPm = getLastDefinedValue(amPmData, formStyle);
return getLastDefinedValue(amPm, width);
}
/**
* Retrieves days of the week for the given locale, using the Gregorian calendar.
*
* @param locale A locale code for the locale format rules to use.
* @param formStyle The required grammatical form.
* @param width The required character width.
* @returns An array of localized name strings.
* For example,`[Sunday, Monday, ... Saturday]` for `en-US`.
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* Use `Intl.DateTimeFormat` for date formating instead.
*/
function getLocaleDayNames(locale, formStyle, width) {
const data = _findLocaleData(locale);
const daysData = [
data[_LocaleDataIndex.DaysFormat],
data[_LocaleDataIndex.DaysStandalone],
];
const days = getLastDefinedValue(daysData, formStyle);
return getLastDefinedValue(days, width);
}
/**
* Retrieves months of the year for the given locale, using the Gregorian calendar.
*
* @param locale A locale code for the locale format rules to use.
* @param formStyle The required grammatical form.
* @param width The required character width.
* @returns An array of localized name strings.
* For example, `[January, February, ...]` for `en-US`.
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* Use `Intl.DateTimeFormat` for date formating instead.
*/
function getLocaleMonthNames(locale, formStyle, width) {
const data = _findLocaleData(locale);
const monthsData = [
data[_LocaleDataIndex.MonthsFormat],
data[_LocaleDataIndex.MonthsStandalone],
];
const months = getLastDefinedValue(monthsData, formStyle);
return getLastDefinedValue(months, width);
}
/**
* Retrieves Gregorian-calendar eras for the given locale.
* @param locale A locale code for the locale format rules to use.
* @param width The required character width.
* @returns An array of localized era strings.
* For example, `[AD, BC]` for `en-US`.
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* Use `Intl.DateTimeFormat` for date formating instead.
*/
function getLocaleEraNames(locale, width) {
const data = _findLocaleData(locale);
const erasData = data[_LocaleDataIndex.Eras];
return getLastDefinedValue(erasData, width);
}
/**
* Retrieves the first day of the week for the given locale.
*
* @param locale A locale code for the locale format rules to use.
* @returns A day index number, using the 0-based week-day index for `en-US`
* (Sunday = 0, Monday = 1, ...).
* For example, for `fr-FR`, returns 1 to indicate that the first day is Monday.
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* Intl's [`getWeekInfo`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getWeekInfo) has partial support (Chromium M99 & Safari 17).
* You may want to rely on the following alternatives:
* - Libraries like [`Luxon`](https://moment.github.io/luxon/#/) rely on `Intl` but fallback on the ISO 8601 definition (monday) if `getWeekInfo` is not supported.
* - Other librairies like [`date-fns`](https://date-fns.org/), [`day.js`](https://day.js.org/en/) or [`weekstart`](https://www.npmjs.com/package/weekstart) library provide their own locale based data for the first day of the week.
*/
function getLocaleFirstDayOfWeek(locale) {
const data = _findLocaleData(locale);
return data[_LocaleDataIndex.FirstDayOfWeek];
}
/**
* Range of week days that are considered the week-end for the given locale.
*
* @param locale A locale code for the locale format rules to use.
* @returns The range of day values, `[startDay, endDay]`.
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* Intl's [`getWeekInfo`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getWeekInfo) has partial support (Chromium M99 & Safari 17).
* Libraries like [`Luxon`](https://moment.github.io/luxon/#/) rely on `Intl` but fallback on the ISO 8601 definition (Saturday+Sunday) if `getWeekInfo` is not supported .
*/
function getLocaleWeekEndRange(locale) {
const data = _findLocaleData(locale);
return data[_LocaleDataIndex.WeekendRange];
}
/**
* Retrieves a localized date-value formatting string.
*
* @param locale A locale code for the locale format rules to use.
* @param width The format type.
* @returns The localized formatting string.
* @see {@link FormatWidth}
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* Use `Intl.DateTimeFormat` for date formating instead.
*/
function getLocaleDateFormat(locale, width) {
const data = _findLocaleData(locale);
return getLastDefinedValue(data[_LocaleDataIndex.DateFormat], width);
}
/**
* Retrieves a localized time-value formatting string.
*
* @param locale A locale code for the locale format rules to use.
* @param width The format type.
* @returns The localized formatting string.
* @see {@link FormatWidth}
* @see [Internationalization (i18n) Guide](guide/i18n)
* @publicApi
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* Use `Intl.DateTimeFormat` for date formating instead.
*/
function getLocaleTimeFormat(locale, width) {
const data = _findLocaleData(locale);
return getLastDefinedValue(data[_LocaleDataIndex.TimeFormat], width);
}
/**
* Retrieves a localized date-time formatting string.
*
* @param locale A locale code for the locale format rules to use.
* @param width The format type.
* @returns The localized formatting string.
* @see {@link FormatWidth}
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* Use `Intl.DateTimeFormat` for date formating instead.
*/
function getLocaleDateTimeFormat(locale, width) {
const data = _findLocaleData(locale);
const dateTimeFormatData = data[_LocaleDataIndex.DateTimeFormat];
return getLastDefinedValue(dateTimeFormatData, width);
}
/**
* Retrieves a localized number symbol that can be used to replace placeholders in number formats.
* @param locale The locale code.
* @param symbol The symbol to localize. Must be one of `NumberSymbol`.
* @returns The character for the localized symbol.
* @see {@link NumberSymbol}
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* Use `Intl.NumberFormat` to format numbers instead.
*/
function getLocaleNumberSymbol(locale, symbol) {
const data = _findLocaleData(locale);
const res = data[_LocaleDataIndex.NumberSymbols][symbol];
if (typeof res === 'undefined') {
if (symbol === NumberSymbol.CurrencyDecimal) {
return data[_LocaleDataIndex.NumberSymbols][NumberSymbol.Decimal];
}
else if (symbol === NumberSymbol.CurrencyGroup) {
return data[_LocaleDataIndex.NumberSymbols][NumberSymbol.Group];
}
}
return res;
}
/**
* Retrieves a number format for a given locale.
*
* Numbers are formatted using patterns, like `#,###.00`. For example, the pattern `#,###.00`
* when used to format the number 12345.678 could result in "12'345,678". That would happen if the
* grouping separator for your language is an apostrophe, and the decimal separator is a comma.
*
* <b>Important:</b> The characters `.` `,` `0` `#` (and others below) are special placeholders
* that stand for the decimal separator, and so on, and are NOT real characters.
* You must NOT "translate" the placeholders. For example, don't change `.` to `,` even though in
* your language the decimal point is written with a comma. The symbols should be replaced by the
* local equivalents, using the appropriate `NumberSymbol` for your language.
*
* Here are the special characters used in number patterns:
*
* | Symbol | Meaning |
* |--------|---------|
* | . | Replaced automatically by the character used for the decimal point. |
* | , | Replaced by the "grouping" (thousands) separator. |
* | 0 | Replaced by a digit (or zero if there aren't enough digits). |
* | # | Replaced by a digit (or nothing if there aren't enough). |
* | ¤ | Replaced by a currency symbol, such as $ or USD. |
* | % | Marks a percent format. The % symbol may change position, but must be retained. |
* | E | Marks a scientific format. The E symbol may change position, but must be retained. |
* | ' | Special characters used as literal characters are quoted with ASCII single quotes. |
*
* @param locale A locale code for the locale format rules to use.
* @param type The type of numeric value to be formatted (such as `Decimal` or `Currency`.)
* @returns The localized format string.
* @see {@link NumberFormatStyle}
* @see [CLDR website](http://cldr.unicode.org/translation/number-patterns)
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* Let `Intl.NumberFormat` determine the number format instead
*/
function getLocaleNumberFormat(locale, type) {
const data = _findLocaleData(locale);
return data[_LocaleDataIndex.NumberFormats][type];
}
/**
* Retrieves the symbol used to represent the currency for the main country
* corresponding to a given locale. For example, '$' for `en-US`.
*
* @param locale A locale code for the locale format rules to use.
* @returns The localized symbol character,
* or `null` if the main country cannot be determined.
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Use the `Intl` API to format a currency with from currency code
*/
function getLocaleCurrencySymbol(locale) {
const data = _findLocaleData(locale);
return data[_LocaleDataIndex.CurrencySymbol] || null;
}
/**
* Retrieves the name of the currency for the main country corresponding
* to a given locale. For example, 'US Dollar' for `en-US`.
* @param locale A locale code for the locale format rules to use.
* @returns The currency name,
* or `null` if the main country cannot be determined.
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Use the `Intl` API to format a currency with from currency code
*/
function getLocaleCurrencyName(locale) {
const data = _findLocaleData(locale);
return data[_LocaleDataIndex.CurrencyName] || null;
}
/**
* Retrieves the default currency code for the given locale.
*
* The default is defined as the first currency which is still in use.
*
* @param locale The code of the locale whose currency code we want.
* @returns The code of the default currency for the given locale.
*
* @publicApi
*
* @deprecated We recommend you create a map of locale to ISO 4217 currency codes.
* Time relative currency data is provided by the CLDR project. See https://www.unicode.org/cldr/charts/44/supplemental/detailed_territory_currency_information.html
*/
function getLocaleCurrencyCode(locale) {
return _getLocaleCurrencyCode(locale);
}
/**
* Retrieves the currency values for a given locale.
* @param locale A locale code for the locale format rules to use.
* @returns The currency values.
* @see [Internationalization (i18n) Guide](guide/i18n)
*/
function getLocaleCurrencies(locale) {
const data = _findLocaleData(locale);
return data[_LocaleDataIndex.Currencies];
}
/**
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* Use `Intl.PluralRules` instead
*/
const getLocalePluralCase = _getLocalePluralCase;
function checkFullData(data) {
if (!data[_LocaleDataIndex.ExtraData]) {
throw new _RuntimeError(2303 /* RuntimeErrorCode.MISSING_EXTRA_LOCALE_DATA_FOR_LOCALE */, ngDevMode &&
`Missing extra locale data for the locale "${data[_LocaleDataIndex.LocaleId]}". Use "registerLocaleData" to load new data. See the "I18n guide" on angular.io to know more.`);
}
}
/**
* Retrieves locale-specific rules used to determine which day period to use
* when more than one period is defined for a locale.
*
* There is a rule for each defined day period. The
* first rule is applied to the first day period and so on.
* Fall back to AM/PM when no rules are available.
*
* A rule can specify a period as time range, or as a single time value.
*
* This functionality is only available when you have loaded the full locale data.
* See the ["I18n guide"](guide/i18n/format-data-locale).
*
* @param locale A locale code for the locale format rules to use.
* @returns The rules for the locale, a single time value or array of *from-time, to-time*,
* or null if no periods are available.
*
* @see {@link getLocaleExtraDayPeriods}
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* Let `Intl.DateTimeFormat` determine the day period instead.
*/
function getLocaleExtraDayPeriodRules(locale) {
const data = _findLocaleData(locale);
checkFullData(data);
const rules = data[_LocaleDataIndex.ExtraData][2 /* ɵExtraLocaleDataIndex.ExtraDayPeriodsRules */] || [];
return rules.map((rule) => {
if (typeof rule === 'string') {
return extractTime(rule);
}
return [extractTime(rule[0]), extractTime(rule[1])];
});
}
/**
* Retrieves locale-specific day periods, which indicate roughly how a day is broken up
* in different languages.
* For example, for `en-US`, periods are morning, noon, afternoon, evening, and midnight.
*
* This functionality is only available when you have loaded the full locale data.
* See the ["I18n guide"](guide/i18n/format-data-locale).
*
* @param locale A locale code for the locale format rules to use.
* @param formStyle The required grammatical form.
* @param width The required character width.
* @returns The translated day-period strings.
* @see {@link getLocaleExtraDayPeriodRules}
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* To extract a day period use `Intl.DateTimeFormat` with the `dayPeriod` option instead.
*/
function getLocaleExtraDayPeriods(locale, formStyle, width) {
const data = _findLocaleData(locale);
checkFullData(data);
const dayPeriodsData = [
data[_LocaleDataIndex.ExtraData][0 /* ɵExtraLocaleDataIndex.ExtraDayPeriodFormats */],
data[_LocaleDataIndex.ExtraData][1 /* ɵExtraLocaleDataIndex.ExtraDayPeriodStandalone */],
];
const dayPeriods = getLastDefinedValue(dayPeriodsData, formStyle) || [];
return getLastDefinedValue(dayPeriods, width) || [];
}
/**
* Retrieves the writing direction of a specified locale
* @param locale A locale code for the locale format rules to use.
* @publicApi
* @returns 'rtl' or 'ltr'
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* For dates and numbers, let `Intl.DateTimeFormat()` and `Intl.NumberFormat()` determine the writing direction.
* The `Intl` alternative [`getTextInfo`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getTextInfo).
* has only partial support (Chromium M99 & Safari 17).
* 3rd party alternatives like [`rtl-detect`](https://www.npmjs.com/package/rtl-detect) can work around this issue.
*/
function getLocaleDirection(locale) {
const data = _findLocaleData(locale);
return data[_LocaleDataIndex.Directionality];
}
/**
* Retrieves the first value that is defined in an array, going backwards from an index position.
*
* To avoid repeating the same data (as when the "format" and "standalone" forms are the same)
* add the first value to the locale data arrays, and add other values only if they are different.
*
* @param data The data array to retrieve from.
* @param index A 0-based index into the array to start from.
* @returns The value immediately before the given index position.
* @see [Internationalization (i18n) Guide](guide/i18n)
*
*/
function getLastDefinedValue(data, index) {
for (let i = index; i > -1; i--) {
if (typeof data[i] !== 'undefined') {
return data[i];
}
}
throw new _RuntimeError(2304 /* RuntimeErrorCode.LOCALE_DATA_UNDEFINED */, ngDevMode && 'Locale data API: locale data undefined');
}
/**
* Extracts the hours and minutes from a string like "15:45"
*/
function extractTime(time) {
const [h, m] = time.split(':');
return { hours: +h, minutes: +m };
}
/**
* Retrieves the currency symbol for a given currency code.
*
* For example, for the default `en-US` locale, the code `USD` can
* be represented by the narrow symbol `$` or the wide symbol `US$`.
*
* @param code The currency code.
* @param format The format, `wide` or `narrow`.
* @param locale A locale code for the locale format rules to use.
*
* @returns The symbol, or the currency code if no symbol is available.
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* You can use `Intl.NumberFormat().formatToParts()` to extract the currency symbol.
* For example: `Intl.NumberFormat('en', {style:'currency', currency: 'USD'}).formatToParts().find(part => part.type === 'currency').value`
* returns `$` for USD currency code in the `en` locale.
* Note: `US$` is a currency symbol for the `en-ca` locale but not the `en-us` locale.
*/
function getCurrencySymbol(code, format, locale = 'en') {
const currency = getLocaleCurrencies(locale)[code] || CURRENCIES_EN[code] || [];
const symbolNarrow = currency[1 /* ɵCurrencyIndex.SymbolNarrow */];
if (format === 'narrow' && typeof symbolNarrow === 'string') {
return symbolNarrow;
}
return currency[0 /* ɵCurrencyIndex.Symbol */] || code;
}
// Most currencies have cents, that's why the default is 2
const DEFAULT_NB_OF_CURRENCY_DIGITS = 2;
/**
* Reports the number of decimal digits for a given currency.
* The value depends upon the presence of cents in that particular currency.
*
* @param code The currency code.
* @returns The number of decimal digits, typically 0 or 2.
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*
* @deprecated Angular recommends relying on the `Intl` API for i18n.
* This function should not be used anymore. Let `Intl.NumberFormat` determine the number of digits to display for the currency
*/
function getNumberOfCurrencyDigits(code) {
let digits;
const currency = CURRENCIES_EN[code];
if (currency) {
digits = currency[2 /* ɵCurrencyIndex.NbOfDigits */];
}
return typeof digits === 'number' ? digits : DEFAULT_NB_OF_CURRENCY_DIGITS;
}
const ISO8601_DATE_REGEX = /^(\d{4,})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
// 1 2 3 4 5 6 7 8 9 10 11
const NAMED_FORMATS = {};
const DATE_FORMATS_SPLIT = /((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/;
/**
* @ngModule CommonModule
* @description
*
* Formats a date according to locale rules.
*
* @param value The date to format, as a Date, or a number (milliseconds since UTC epoch)
* or an [ISO date-time string](https://www.w3.org/TR/NOTE-datetime).
* @param format The date-time components to include. See `DatePipe` for details.
* @param locale A locale code for the locale format rules to use.
* @param timezone The time zone. A time zone offset from GMT (such as `'+0430'`).
* If not specified, uses host system settings.
*
* @returns The formatted date string.
*
* @see {@link DatePipe}
* @see [Internationalization (i18n) Guide](guide/i18n)
*
* @publicApi
*/
function formatDate(value, format, locale, timezone) {
let date = toDate(value);
const namedFormat = getNamedFormat(locale, format);
format = namedFormat || format;
let parts = [];
let match;
while (format) {
match = DATE_FORMATS_SPLIT.exec(format);
if (match) {
parts = parts.concat(match.slice(1));
const part = parts.pop();
if (!part) {
break;
}
format = part;
}
else {
parts.push(format);
break;
}
}
if (typeof ngDevMode === 'undefined' || ngDevMode) {
assertValidDateFormat(parts);
}
let dateTimezoneOffset = date.getTimezoneOffset();
if (timezone) {
dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
date = convertTimezoneToLocal(date, timezone);
}
let text = '';
parts.forEach((value) => {
const dateFormatter = getDateFormatter(value);
text += dateFormatter
? dateFormatter(date, locale, dateTimezoneOffset)
: value === "''"
? "'"
: value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
});
return text;
}
/**
* Asserts that the given date format is free from common mistakes. Throws an
* error if one is found (except for the case of all "Y", in which case we just
* log a warning). This should only be called in development mode.
*/
function assertValidDateFormat(parts) {
if (parts.some((part) => /^Y+$/.test(part)) && !parts.some((part) => /^w+$/.test(part))) {
// "Y" indicates "week-based year", which differs from the actual calendar
// year for a few days around Jan 1 most years. Unless "w" is also
// present (e.g. a date like "2024-W52") this is likely a mistake. Users
// probably meant "y" instead.
const message = `Suspicious use of week-based year "Y" in date pattern "${parts.join('')}". Did you mean to use calendar year "y" instead?`;
if (parts.length === 1) {
// NOTE: allow "YYYY" with just a warning, since it's used in tests.
console.error(_formatRuntimeError(2300 /* RuntimeErrorCode.SUSPICIOUS_DATE_FORMAT */, message));
}
else {
throw new _RuntimeError(2300 /* RuntimeErrorCode.SUSPICIOUS_DATE_FORMAT */, message);
}
}
}
/**
* Create a new Date object with the given date value, and the time set to midnight.
*
* We cannot use `new Date(year, month, date)` because it maps years between 0 and 99 to 1900-1999.
* See: https://github.com/angular/angular/issues/40377
*
* Note that this function returns a Date object whose time is midnight in the current locale's
* timezone. In the future we might want to change this to be midnight in UTC, but this would be a
* considerable breaking change.
*/
function createDate(year, month, date) {
// The `newDate` is set to midnight (UTC) on January 1st 1970.
// - In PST this will be December 31st 1969 at 4pm.
// - In GMT this will be January 1st 1970 at 1am.
// Note that they even have different years, dates and months!
const newDate = new Date(0);
// `setFullYear()` allows years like 0001 to be set correctly. This function does not
// change the internal time of the date.
// Consider calling `setFullYear(2019, 8, 20)` (September 20, 2019).
// - In PST this will now be September 20, 2019 at 4pm
// - In GMT this will now be September 20, 2019 at 1am
newDate.setFullYear(year, month, date);
// We want the final date to be at local midnight, so we reset the time.
// - In PST this will now be September 20, 2019 at 12am
// - In GMT this will now be September 20, 2019 at 12am
newDate.setHours(0, 0, 0);
return newDate;
}
function getNamedFormat(locale, format) {
const localeId = getLocaleId(locale);
NAMED_FORMATS[localeId] ??= {};
if (NAMED_FORMATS[localeId][format]) {
return NAMED_FORMATS[localeId][format];
}
let formatValue = '';
switch (format) {
case 'shortDate':
formatValue = getLocaleDateFormat(locale, FormatWidth.Short);
break;
case 'mediumDate':
formatValue = getLocaleDateFormat(locale, FormatWidth.Medium);
break;
case 'longDate':
formatValue = getLocaleDateFormat(locale, FormatWidth.Long);
break;
case 'fullDate':
formatValue = getLocaleDateFormat(locale, FormatWidth.Full);
break;
case 'shortTime':
formatValue = getLocaleTimeFormat(locale, FormatWidth.Short);
break;
case 'mediumTime':
formatValue = getLocaleTimeFormat(locale, FormatWidth.Medium);
break;
case 'longTime':
formatValue = getLocaleTimeFormat(locale, FormatWidth.Long);
break;
case 'fullTime':
formatValue = getLocaleTimeFormat(locale, FormatWidth.Full);
break;
case 'short':
const shortTime = getNamedFormat(locale, 'shortTime');
const shortDate = getNamedFormat(locale, 'shortDate');
formatValue = formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Short), [
shortTime,
shortDate,
]);
break;
case 'medium':
const mediumTime = getNamedFormat(locale, 'mediumTime');
const mediumDate = getNamedFormat(locale, 'mediumDate');
formatValue = formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Medium), [
mediumTime,
mediumDate,
]);
break;
case 'long':
const longTime = getNamedFormat(locale, 'longTime');
const longDate = getNamedFormat(locale, 'longDate');
formatValue = formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Long), [
longTime,
longDate,
]);
break;
case 'full':
const fullTime = getNamedFormat(locale, 'fullTime');
const fullDate = getNamedFormat(locale, 'fullDate');
formatValue = formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Full), [
fullTime,
fullDate,
]);
break;
}
if (formatValue) {
NAMED_FORMATS[localeId][format] = formatValue;
}
return formatValue;
}
function formatDateTime(str, opt_values) {
if (opt_values) {
str = str.replace(/\{([^}]+)}/g, function (match, key) {
return opt_values != null && key in opt_values ? opt_values[key] : match;
});
}
return str;
}
function padNumber(num, digits, minusSign = '-', trim, negWrap) {
let neg = '';
if (num < 0 || (negWrap && num <= 0)) {
if (negWrap) {
num = -num + 1;
}
else {
num = -num;
neg = minusSign;
}
}
let strNum = String(num);
while (strNum.length < digits) {
strNum = '0' + strNum;
}
if (trim) {
strNum = strNum.slice(strNum.length - digits);
}
return neg + strNum;
}
function formatFractionalSeconds(milliseconds, digits) {
const strMs = padNumber(milliseconds, 3);
return strMs.substring(0, digits);
}
/**
* Returns a date formatter that transforms a date into its locale digit representation
*/
function dateGetter(name, size, offset = 0, trim = false, negWrap = false) {
return function (date, locale) {
let part = getDatePart(name, date);
if (offset > 0 || part > -offset) {
part += offset;
}
if (name === 3 /* DateType.Hours */) {
if (part === 0 && offset === -12) {
part = 12;
}
}
else if (name === 6 /* DateType.FractionalSeconds */) {
return formatFractionalSeconds(part, size);
}
const localeMinus = getLocaleNumberSymbol(locale, NumberSymbol.MinusSign);
return padNumber(part, size, localeMinus, trim, negWrap);
};
}
function getDatePart(part, date) {
switch (part) {
case 0 /* DateType.FullYear */:
return date.getFullYear();
case 1 /* DateType.Month */:
return date.getMonth();
case 2 /* DateType.Date */:
return date.getDate();
case 3 /* DateType.Hours */:
return date.getHours();
case 4 /* DateType.Minutes */:
return date.getMinutes();
case 5 /* DateType.Seconds */:
return date.getSeconds();
case 6 /* DateType.FractionalSeconds */:
return date.getMilliseconds();
case 7 /* DateType.Day */:
return date.getDay();
default:
throw new _RuntimeError(2301 /* RuntimeErrorCode.UNKNOWN_DATE_TYPE_VALUE */, ngDevMode && `Unknown DateType value "${part}".`);
}
}
/**
* Returns a date formatter that transforms a date into its locale string representation
*/
function dateStrGetter(name, width, form = FormStyle.Format, extended = false) {
return function (date, locale) {
return getDateTranslation(date, locale, name, width, form, extended);
};
}
/**
* Returns the locale translation of a date for a given form, type and width
*/
function getDateTranslation(date, locale, name, width, form, extended) {
switch (name) {
case 2 /* TranslationType.Months */:
return getLocaleMonthNames(locale, form, width)[date.getMonth()];
case 1 /* TranslationType.Days */:
return getLocaleDayNames(locale, form, width)[date.getDay()];
case 0 /* TranslationType.DayPeriods */:
const currentHours = date.getHours();
const currentMinutes = date.getMinutes();
if (extended) {
const rules = getLocaleExtraDayPeriodRules(locale);
const dayPeriods = getLocaleExtraDayPeriods(locale, form, width);
const index = rules.findIndex((rule) => {
if (Array.isArray(rule)) {
// morning, afternoon, evening, night
const [from, to] = rule;
const afterFrom = currentHours >= from.hours && currentMinutes >= from.minutes;
const beforeTo = currentHours < to.hours || (currentHours === to.hours && currentMinutes < to.minutes);
// We must account for normal rules that span a period during the day (e.g. 6am-9am)
// where `from` is less (earlier) than `to`. But also rules that span midnight (e.g.
// 10pm - 5am) where `from` is greater (later!) than `to`.
//
// In the first case the current time must be BOTH after `from` AND before `to`
// (e.g. 8am is after 6am AND before 10am).
//
// In the second case the current time must be EITHER after `from` OR before `to`
// (e.g. 4am is before 5am but not after 10pm; and 11pm is not before 5am but it is
// after 10pm).
if (from.hours < to.hours) {
if (afterFrom && beforeTo) {
return true;
}
}
else if (afterFrom || beforeTo) {
return true;
}
}
else {
// noon or midnight
if (rule.hours === currentHours && rule.minutes === currentMinutes) {
return true;
}
}
return false;
});
if (index !== -1) {
return dayPeriods[index];
}
}
// if no rules for the day periods, we use am/pm by default
return getLocaleDayPeriods(locale, form, width)[currentHours < 12 ? 0 : 1];
case 3 /* TranslationType.Eras */:
return getLocaleEraNames(locale, width)[date.getFullYear() <= 0 ? 0 : 1];
default:
// This default case is not needed by TypeScript compiler, as the switch is exhaustive.
// However Closure Compiler does not understand that and reports an error in typed mode.
// The `throw new Error` below works around the problem, and the unexpected: never variable
// makes sure tsc still checks this code is unreachable.
const unexpected = name;
throw new _RuntimeError(2302 /* RuntimeErrorCode.UNEXPECTED_TRANSLATION_TYPE */, ngDevMode && `unexpected translation type ${unexpected}`);
}
}
/**
* Returns a date formatter that transforms a date and an offset into a timezone with ISO8601 or
* GMT format depending on the width (eg: short = +0430, short:GMT = GMT+4, long = GMT+04:30,
* extended = +04:30)
*/
function timeZoneGetter(width) {
return function (date, locale, offset) {
const zone = -1 * offset;
const minusSign = getLocaleNumberSymbol(locale, NumberSymbol.MinusSign);
const hours = zone > 0 ? Math.floor(zone / 60) : Math.ceil(zone / 60);
switch (width) {
case 0 /* ZoneWidth.Short */:
return ((zone >= 0 ? '+' : '') +
padNumber(hours, 2, minusSign) +
padNumber(Math.abs(zone % 60), 2, minusSign));
case 1 /* ZoneWidth.ShortGMT */:
return 'GMT' + (zone >= 0 ? '+' : '') + padNumber(hours, 1, minusSign);
case 2 /* ZoneWidth.Long */: