UNPKG

@angular/common

Version:

Angular - commonly needed directives and services

1,163 lines (1,155 loc) 209 kB
/** * @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 */: