Skip to content
26 changes: 26 additions & 0 deletions projects/igniteui-angular/calendar/src/calendar/day-digit.pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Pipe, PipeTransform } from '@angular/core';
import { IFormattingViews } from "./calendar";

@Pipe({
name: 'dayDigit',
standalone: true
})
export class DayDigitPipe implements PipeTransform {
public transform(value: string, formatViews: IFormattingViews): string {
if (!value) {
return '';
}

// strip non-numeric characters that might have been added by the locale formatter (e.g., "25日" -> "25").
if (formatViews.day) {
// Use regex to extract the numeric day value.
// This handles locales that include non-numeric characters (e.g. '25日' in zh-CN).
// match(/\d+/) is preferred over parseInt() as it robustly finds the digits regardless
// of their position (prefix/suffix) in the localized string.
const match = value.match(/\d+/);
return match ? match[0] : value;
}

return value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
(mouseEnter)="changePreviewRange(day.native)"
(mouseLeave)="clearPreviewRange()"
>
{{ formattedDate(day.native) }}
{{ formattedDate(day.native) | dayDigit:formatViews }}
</igx-day-item>
}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ScrollDirection } from "../calendar";
import { KeyboardNavigationService } from '../calendar.services';
import { CalendarDay } from 'igniteui-angular/core';
import { UIInteractions } from '../../../../test-utils/ui-interactions.spec';
import { DayDigitPipe } from "igniteui-angular/calendar/src/calendar/day-digit.pipe";

const TODAY = new Date(2024, 6, 12);

Expand Down Expand Up @@ -114,6 +115,37 @@ describe("Days View Component", () => {
}
});

it("should format date correctly for zh-CN locale programmatically vs template pipe", () => {
const fixture = TestBed.createComponent(InitDaysViewComponent);
const daysView = fixture.componentInstance.instance;
const pipe = new DayDigitPipe();
const date = new Date(2020, 10, 25); // Nov 25

// Initialize component
daysView.formatViews = { day: true, month: true, year: true };
fixture.detectChanges();

// Mock the formatter behavior
// Simulate a locale (like zh-CN) that adds a suffix to the day number.
// Cast to 'any' to overwrite the protected 'formatterDay' property used by formattedDate()
(daysView as any).formatterDay = {
format: () => '25日',
} as Intl.DateTimeFormat;

// 1. Verify Programmatic Access (formattedDate method)
// Should return the raw formatted string from the formatter (with suffix)
const programmaticResult = daysView.formattedDate(date);
expect(programmaticResult).toBe('25日', 'Programmatic API should return the full locale string (including suffix, in this case 日)');

// 2. Verify Pipe Logic
// The pipe takes the formatted string "25日" and strips non-digits to return "25"
const pipeResult = pipe.transform(programmaticResult, daysView.formatViews);
expect(pipeResult).toBe('25', 'Pipe should strip non-numeric characters from the input string');

// 3. Confirm the difference implies the pipe did its job
expect(programmaticResult).not.toEqual(pipeResult);
});

describe("Keyboard navigation", () => {
let fixture: ComponentFixture<InitDaysViewComponent>;
let el: HTMLElement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
import { IgxCalendarBaseDirective } from '../calendar-base';
import { IViewChangingEventArgs } from './days-view.interface';
import { KeyboardNavigationService } from '../calendar.services';
import { DayDigitPipe } from "../day-digit.pipe";

let NEXT_ID = 0;

Expand All @@ -52,7 +53,7 @@ let NEXT_ID = 0;
selector: 'igx-days-view',
templateUrl: 'days-view.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [IgxDayItemComponent, TitleCasePipe]
imports: [IgxDayItemComponent, TitleCasePipe, DayDigitPipe]
})
export class IgxDaysViewComponent extends IgxCalendarBaseDirective implements AfterContentChecked {
protected el = inject(ElementRef);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2516,6 +2516,7 @@
letter-spacing: sizable(var(--ig-body-2-letter-spacing), var(--ig-body-2-letter-spacing), var(--ig-body-1-letter-spacing));
text-transform: sizable(var(--ig-body-2-text-transform), var(--ig-body-2-text-transform), var(--ig-body-1-text-transform));
margin: 0;
white-space: nowrap;
}
}

Expand All @@ -2528,6 +2529,7 @@
letter-spacing: sizable(var(--ig-body-2-letter-spacing), var(--ig-body-2-letter-spacing), var(--ig-body-1-letter-spacing));
text-transform: sizable(var(--ig-body-2-text-transform), var(--ig-body-2-text-transform), var(--ig-body-1-text-transform));
margin: 0;
white-space: nowrap;
}
}
}
1 change: 1 addition & 0 deletions src/app/calendar/calendar.sample.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
[showWeekNumbers]="properties.showWeekNumbers"
[hasHeader]="!properties.hideHeader"
[formatOptions]="formatOptions"
[formatViews]="formatViews"
[disabledDates]="disabledDates"
[specialDates]="specialDates"
(selected)="onSelection($event)"
Expand Down
11 changes: 11 additions & 0 deletions src/app/calendar/calendar.sample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
DateRange,
DateRangeDescriptor,
DateRangeType,
IFormattingViews,
} from 'igniteui-angular';
import {
Properties,
Expand Down Expand Up @@ -62,6 +63,12 @@ export class CalendarSampleComponent implements OnInit {
year: 'numeric',
};

protected formatViews: IFormattingViews = {
day: true,
month: true,
year: true
};

public panelConfig: PropertyPanelConfig = {
locale: {
label: 'Change Locale',
Expand All @@ -87,6 +94,10 @@ export class CalendarSampleComponent implements OnInit {
{
value: 'ja-JP',
label: 'JP'
},
{
value: 'zh-CN',
label: 'CN'
}
],
defaultValue: 'en-US'
Expand Down
Loading