fix(common): mark locale data arrays as readonly (#30397)
To discourage developers from mutating the arrays returned from the following methods, their return types have been marked as readonly. * `getLocaleDayPeriods()` * `getLocaleDayNames()` * `getLocaleMonthNames()` * `getLocaleEraNames()` Fixes #27003 BREAKING CHANGE: The locale data API has been marked as returning readonly arrays, rather than mutable arrays, since these arrays are shared across calls to the API. If you were mutating them (e.g. calling `sort()`, `push()`, `splice()`, etc) then your code will not longer compile. If you need to mutate the array, you should now take a copy (e.g. by calling `slice()`) and mutate the copy. PR Close #30397
This commit is contained in:
parent
2d52c80332
commit
6acea54f62
|
@ -61,13 +61,13 @@ export declare function getLocaleDateFormat(locale: string, width: FormatWidth):
|
|||
|
||||
export declare function getLocaleDateTimeFormat(locale: string, width: FormatWidth): string;
|
||||
|
||||
export declare function getLocaleDayNames(locale: string, formStyle: FormStyle, width: TranslationWidth): string[];
|
||||
export declare function getLocaleDayNames(locale: string, formStyle: FormStyle, width: TranslationWidth): ReadonlyArray<string>;
|
||||
|
||||
export declare function getLocaleDayPeriods(locale: string, formStyle: FormStyle, width: TranslationWidth): [string, string];
|
||||
export declare function getLocaleDayPeriods(locale: string, formStyle: FormStyle, width: TranslationWidth): Readonly<[string, string]>;
|
||||
|
||||
export declare function getLocaleDirection(locale: string): 'ltr' | 'rtl';
|
||||
|
||||
export declare function getLocaleEraNames(locale: string, width: TranslationWidth): [string, string];
|
||||
export declare function getLocaleEraNames(locale: string, width: TranslationWidth): Readonly<[string, string]>;
|
||||
|
||||
export declare function getLocaleExtraDayPeriodRules(locale: string): (Time | [Time, Time])[];
|
||||
|
||||
|
@ -77,7 +77,7 @@ export declare function getLocaleFirstDayOfWeek(locale: string): WeekDay;
|
|||
|
||||
export declare function getLocaleId(locale: string): string;
|
||||
|
||||
export declare function getLocaleMonthNames(locale: string, formStyle: FormStyle, width: TranslationWidth): string[];
|
||||
export declare function getLocaleMonthNames(locale: string, formStyle: FormStyle, width: TranslationWidth): ReadonlyArray<string>;
|
||||
|
||||
export declare function getLocaleNumberFormat(locale: string, type: NumberFormatStyle): string;
|
||||
|
||||
|
|
|
@ -233,7 +233,7 @@ export function getLocaleId(locale: string): string {
|
|||
* @publicApi
|
||||
*/
|
||||
export function getLocaleDayPeriods(
|
||||
locale: string, formStyle: FormStyle, width: TranslationWidth): [string, string] {
|
||||
locale: string, formStyle: FormStyle, width: TranslationWidth): Readonly<[string, string]> {
|
||||
const data = ɵfindLocaleData(locale);
|
||||
const amPmData = <[string, string][][]>[
|
||||
data[ɵLocaleDataIndex.DayPeriodsFormat], data[ɵLocaleDataIndex.DayPeriodsStandalone]
|
||||
|
@ -255,7 +255,7 @@ export function getLocaleDayPeriods(
|
|||
* @publicApi
|
||||
*/
|
||||
export function getLocaleDayNames(
|
||||
locale: string, formStyle: FormStyle, width: TranslationWidth): string[] {
|
||||
locale: string, formStyle: FormStyle, width: TranslationWidth): ReadonlyArray<string> {
|
||||
const data = ɵfindLocaleData(locale);
|
||||
const daysData =
|
||||
<string[][][]>[data[ɵLocaleDataIndex.DaysFormat], data[ɵLocaleDataIndex.DaysStandalone]];
|
||||
|
@ -276,7 +276,7 @@ export function getLocaleDayNames(
|
|||
* @publicApi
|
||||
*/
|
||||
export function getLocaleMonthNames(
|
||||
locale: string, formStyle: FormStyle, width: TranslationWidth): string[] {
|
||||
locale: string, formStyle: FormStyle, width: TranslationWidth): ReadonlyArray<string> {
|
||||
const data = ɵfindLocaleData(locale);
|
||||
const monthsData =
|
||||
<string[][][]>[data[ɵLocaleDataIndex.MonthsFormat], data[ɵLocaleDataIndex.MonthsStandalone]];
|
||||
|
@ -287,7 +287,6 @@ export function getLocaleMonthNames(
|
|||
/**
|
||||
* Retrieves Gregorian-calendar eras 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 era strings.
|
||||
|
@ -296,7 +295,8 @@ export function getLocaleMonthNames(
|
|||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export function getLocaleEraNames(locale: string, width: TranslationWidth): [string, string] {
|
||||
export function getLocaleEraNames(
|
||||
locale: string, width: TranslationWidth): Readonly<[string, string]> {
|
||||
const data = ɵfindLocaleData(locale);
|
||||
const erasData = <[string, string][]>data[ɵLocaleDataIndex.Eras];
|
||||
return getLastDefinedValue(erasData, width);
|
||||
|
|
|
@ -13,7 +13,7 @@ import localeHe from '@angular/common/locales/he';
|
|||
import localeZh from '@angular/common/locales/zh';
|
||||
import {ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core';
|
||||
|
||||
import {FormatWidth, getCurrencySymbol, getLocaleDateFormat, getLocaleDirection, getNumberOfCurrencyDigits} from '../../src/i18n/locale_data_api';
|
||||
import {FormatWidth, FormStyle, getCurrencySymbol, getLocaleDateFormat, getLocaleDayNames, getLocaleDirection, getLocaleMonthNames, getNumberOfCurrencyDigits, TranslationWidth} from '../../src/i18n/locale_data_api';
|
||||
|
||||
{
|
||||
describe('locale data api', () => {
|
||||
|
@ -71,5 +71,96 @@ import {FormatWidth, getCurrencySymbol, getLocaleDateFormat, getLocaleDirection,
|
|||
expect(getLocaleDirection('en')).toEqual('ltr');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLocaleDayNames', () => {
|
||||
it('should return english short list of days', () => {
|
||||
expect(
|
||||
getLocaleDayNames('en-US', FormStyle.Format, TranslationWidth.Short),
|
||||
)
|
||||
.toEqual(['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']);
|
||||
});
|
||||
|
||||
it('should return french short list of days', () => {
|
||||
expect(
|
||||
getLocaleDayNames('fr-CA', FormStyle.Format, TranslationWidth.Short),
|
||||
)
|
||||
.toEqual(['di', 'lu', 'ma', 'me', 'je', 've', 'sa']);
|
||||
});
|
||||
|
||||
it('should return english wide list of days', () => {
|
||||
expect(
|
||||
getLocaleDayNames('en-US', FormStyle.Format, TranslationWidth.Wide),
|
||||
)
|
||||
.toEqual(
|
||||
['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']);
|
||||
});
|
||||
|
||||
it('should return french wide list of days', () => {
|
||||
expect(
|
||||
getLocaleDayNames('fr-CA', FormStyle.Format, TranslationWidth.Wide),
|
||||
)
|
||||
.toEqual(['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi']);
|
||||
});
|
||||
|
||||
it('should return the full short list of days after manipulations', () => {
|
||||
const days =
|
||||
Array.from(getLocaleDayNames('en-US', FormStyle.Format, TranslationWidth.Short));
|
||||
|
||||
days.splice(2);
|
||||
days.push('unexisting_day');
|
||||
|
||||
const newDays = getLocaleDayNames('en-US', FormStyle.Format, TranslationWidth.Short);
|
||||
|
||||
expect(newDays.length).toBe(7);
|
||||
|
||||
expect(newDays).toEqual(['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLocaleMonthNames', () => {
|
||||
it('should return english abbreviated list of month', () => {
|
||||
expect(getLocaleMonthNames('en-US', FormStyle.Format, TranslationWidth.Abbreviated))
|
||||
.toEqual([
|
||||
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return french abbreviated list of month', () => {
|
||||
expect(getLocaleMonthNames('fr-CA', FormStyle.Format, TranslationWidth.Abbreviated))
|
||||
.toEqual([
|
||||
'janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.',
|
||||
'nov.', 'déc.'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return english wide list of month', () => {
|
||||
expect(getLocaleMonthNames('en-US', FormStyle.Format, TranslationWidth.Wide)).toEqual([
|
||||
'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September',
|
||||
'October', 'November', 'December'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return french wide list of month', () => {
|
||||
expect(getLocaleMonthNames('fr-CA', FormStyle.Format, TranslationWidth.Wide)).toEqual([
|
||||
'janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre',
|
||||
'octobre', 'novembre', 'décembre'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return the full abbreviated list of month after manipulations', () => {
|
||||
const month = Array.from(
|
||||
getLocaleMonthNames('en-US', FormStyle.Format, TranslationWidth.Abbreviated));
|
||||
month.splice(2);
|
||||
month.push('unexisting_month');
|
||||
|
||||
const newMonth =
|
||||
getLocaleMonthNames('en-US', FormStyle.Format, TranslationWidth.Abbreviated);
|
||||
|
||||
expect(newMonth.length).toBe(12);
|
||||
|
||||
expect(newMonth).toEqual(
|
||||
['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue