Skip to content

Commit 8a3b28c

Browse files
committed
refactor(*): New localization initial implementation.
1 parent 6bdd10f commit 8a3b28c

32 files changed

+375
-130
lines changed

projects/igniteui-angular/src/lib/action-strip/action-strip.component.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { getCurrentResourceStrings } from '../core/i18n/resources';
2929
import { IgxIconButtonDirective } from '../directives/button/icon-button.directive';
3030
import { IgxActionStripToken } from './token';
3131
import { trackByIdentity } from '../core/utils';
32+
import { getI18nManager } from 'igniteui-i18n-core';
3233

3334
@Directive({
3435
selector: '[igxActionStripMenuItem]',
@@ -197,7 +198,11 @@ export class IgxActionStripComponent implements IgxActionStripToken, AfterConten
197198
protected el: ElementRef,
198199
/** @hidden @internal **/
199200
public cdr: ChangeDetectorRef,
200-
) { }
201+
) {
202+
getI18nManager().onResourceChange(() => {
203+
this._resourceStrings = getCurrentResourceStrings(ActionStripResourceStringsEN, false);
204+
});
205+
}
201206

202207
/**
203208
* Menu Items list.

projects/igniteui-angular/src/lib/banner/banner.component.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { IgxExpansionPanelBodyComponent } from '../expansion-panel/expansion-pan
2020
import { IgxExpansionPanelComponent } from '../expansion-panel/expansion-panel.component';
2121
import { BannerResourceStringsEN, IBannerResourceStrings } from '../core/i18n/banner-resources';
2222
import { getCurrentResourceStrings } from '../core/i18n/resources';
23+
import { getI18nManager } from 'igniteui-i18n-core';
2324

2425
export interface BannerEventArgs extends IBaseEventArgs {
2526
event?: Event;
@@ -237,7 +238,11 @@ export class IgxBannerComponent implements IToggleView {
237238
private _animationSettings: ToggleAnimationSettings;
238239
private _resourceStrings = getCurrentResourceStrings(BannerResourceStringsEN);
239240

240-
constructor(public elementRef: ElementRef<HTMLElement>) { }
241+
constructor(public elementRef: ElementRef<HTMLElement>) {
242+
getI18nManager().onResourceChange(() => {
243+
this._resourceStrings = getCurrentResourceStrings(BannerResourceStringsEN, false);
244+
});
245+
}
241246

242247
/**
243248
* Opens the banner

projects/igniteui-angular/src/lib/calendar/calendar-base.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { getCurrentResourceStrings } from '../core/i18n/resources';
1111
import { KeyboardNavigationService } from './calendar.services';
1212
import { getYearRange, isDateInRanges } from './common/helpers';
1313
import { CalendarDay } from './common/model';
14+
import { getI18nManager } from 'igniteui-i18n-core';
1415

1516
/** @hidden @internal */
1617
@Directive({
@@ -659,6 +660,10 @@ export class IgxCalendarBaseDirective implements ControlValueAccessor {
659660
this.locale = _localeId;
660661
this.viewDate = this.viewDate ? this.viewDate : new Date();
661662
this.initFormatters();
663+
664+
getI18nManager().onResourceChange(() => {
665+
this._resourceStrings = getCurrentResourceStrings(CalendarResourceStringsEN, false);
666+
});
662667
}
663668

664669
/**

projects/igniteui-angular/src/lib/carousel/carousel.component.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import { getCurrentResourceStrings } from '../core/i18n/resources';
4040
import { HammerGesturesManager } from '../core/touch';
4141
import { CarouselAnimationType, CarouselIndicatorsOrientation } from './enums';
4242
import { IgxDirectionality } from '../services/direction/directionality';
43+
import { getI18nManager } from 'igniteui-i18n-core';
4344

4445
let NEXT_ID = 0;
4546

@@ -576,6 +577,9 @@ export class IgxCarouselComponent extends IgxCarouselComponentBase implements On
576577
) {
577578
super(animationService, cdr);
578579
this.differ = this.iterableDiffers.find([]).create(null);
580+
getI18nManager().onResourceChange(() => {
581+
this._resourceStrings = getCurrentResourceStrings(CarouselResourceStringsEN, false);
582+
});
579583
}
580584

581585
/** @hidden */

projects/igniteui-angular/src/lib/chips/chip.component.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { IgxIconComponent } from '../icon/icon.component';
2424
import { NgClass, NgTemplateOutlet } from '@angular/common';
2525
import { getCurrentResourceStrings } from '../core/i18n/resources';
2626
import { Size } from '../grids/common/enums';
27+
import { getI18nManager } from 'igniteui-i18n-core';
2728

2829
export const IgxChipTypeVariant = {
2930
PRIMARY: 'primary',
@@ -610,7 +611,11 @@ export class IgxChipComponent implements OnInit, OnDestroy {
610611
public cdr: ChangeDetectorRef,
611612
private ref: ElementRef<HTMLElement>,
612613
private renderer: Renderer2,
613-
@Inject(DOCUMENT) public document: any) { }
614+
@Inject(DOCUMENT) public document: any) {
615+
getI18nManager().onResourceChange(() => {
616+
this._resourceStrings = getCurrentResourceStrings(ChipResourceStringsEN, false);
617+
});
618+
}
614619

615620
/**
616621
* @hidden

projects/igniteui-angular/src/lib/combo/combo.common.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import { IComboItemAdditionEvent, IComboSearchInputEventArgs } from './public_ap
4747
import { ComboResourceStringsEN, IComboResourceStrings } from '../core/i18n/combo-resources';
4848
import { getCurrentResourceStrings } from '../core/i18n/resources';
4949
import { isEqual } from 'lodash-es';
50+
import { getI18nManager } from 'igniteui-i18n-core';
5051

5152
export const IGX_COMBO_COMPONENT = /*@__PURE__*/new InjectionToken<IgxComboBase>('IgxComboComponentToken');
5253

@@ -967,7 +968,11 @@ export abstract class IgxComboBaseDirective implements IgxComboBase, AfterViewCh
967968
@Optional() @Inject(IGX_INPUT_GROUP_TYPE) protected _inputGroupType: IgxInputGroupType,
968969
@Optional() protected _injector: Injector,
969970
@Optional() @Inject(IgxIconService) protected _iconService?: IgxIconService,
970-
) { }
971+
) {
972+
getI18nManager().onResourceChange(() => {
973+
this._resourceStrings = getCurrentResourceStrings(ComboResourceStringsEN, false);
974+
});
975+
}
971976

972977
public ngAfterViewChecked() {
973978
const targetElement = this.inputGroup.element.nativeElement.querySelector('.igx-input-group__bundle') as HTMLElement;

projects/igniteui-angular/src/lib/core/i18n/resources.ts

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,48 +13,54 @@ import { IActionStripResourceStrings } from './action-strip-resources';
1313
import { IQueryBuilderResourceStrings } from './query-builder-resources';
1414
import { IComboResourceStrings } from './combo-resources';
1515
import { IBannerResourceStrings } from './banner-resources';
16+
import {
17+
registerI18n,
18+
getCurrentResourceStrings as getCurrentResourceStringsCore,
19+
IResourceStrings as IResourceStringsCore
20+
} from 'igniteui-i18n-core';
1621

1722
export interface IResourceStrings extends IGridResourceStrings, ITimePickerResourceStrings, ICalendarResourceStrings,
1823
ICarouselResourceStrings, IChipResourceStrings, IComboResourceStrings, IInputResourceStrings, IDatePickerResourceStrings,
1924
IDateRangePickerResourceStrings, IListResourceStrings, IPaginatorResourceStrings, ITreeResourceStrings,
2025
IActionStripResourceStrings, IQueryBuilderResourceStrings, IBannerResourceStrings { }
2126

22-
export class igxI18N {
23-
private static _instance: igxI18N;
24-
25-
private _currentResourceStrings: IResourceStrings = { };
26-
27-
private constructor() { }
28-
29-
public static instance() {
30-
return this._instance || (this._instance = new this());
27+
function igxRegisterI18n(resourceStrings: IResourceStrings) {
28+
// Remove `igx_` prefix for compatibility with older versions.
29+
const genericResourceStrings: IResourceStringsCore = {};
30+
for (const key of Object.keys(resourceStrings)) {
31+
let stringKey = key;
32+
if (stringKey.startsWith("igx_")) {
33+
stringKey = stringKey.replace("igx_", "");
34+
}
35+
genericResourceStrings[stringKey] = resourceStrings[key];
3136
}
37+
registerI18n(genericResourceStrings);
38+
}
3239

33-
/**
34-
* Changes the resource strings for all components in the application
35-
* ```
36-
* @param resourceStrings to be applied
37-
*/
38-
public changei18n(resourceStrings: IResourceStrings) {
39-
for (const key of Object.keys(resourceStrings)) {
40-
this._currentResourceStrings[key] = resourceStrings[key];
41-
}
40+
/** Get current resource strings based on default. Result is truncated result, containing only relevant locale strings. */
41+
export function getCurrentResourceStrings<T>(defaultEN: T, init = true) {
42+
const igxResourceStringKeys = Object.keys(defaultEN);
43+
if (init) {
44+
igxRegisterI18n(defaultEN);
4245
}
4346

44-
public getCurrentResourceStrings(en: IResourceStrings): IResourceStrings {
45-
for (const key of Object.keys(en)) {
46-
if (!this._currentResourceStrings[key]) {
47-
this._currentResourceStrings[key] = en[key];
48-
}
47+
// Append back `igx_` prefix for compatibility with older versions.
48+
const resourceStrings = getCurrentResourceStringsCore();
49+
const normalizedResourceStrings: T = {} as T;
50+
const resourceStringsKeys = Object.keys(resourceStrings);
51+
for (const key of resourceStringsKeys) {
52+
let stringKey = key;
53+
if (!stringKey.startsWith("igx_")) {
54+
stringKey = "igx_" + stringKey;
55+
}
56+
if (igxResourceStringKeys.includes(stringKey)) {
57+
normalizedResourceStrings[stringKey] = resourceStrings[key];
4958
}
50-
return this._currentResourceStrings;
5159
}
52-
}
5360

54-
export function getCurrentResourceStrings(en: IResourceStrings) {
55-
return igxI18N.instance().getCurrentResourceStrings(en);
61+
return normalizedResourceStrings;
5662
}
5763

5864
export function changei18n(resourceStrings: IResourceStrings) {
59-
igxI18N.instance().changei18n(resourceStrings);
65+
igxRegisterI18n(resourceStrings);
6066
}

projects/igniteui-angular/src/lib/core/utils.ts

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { NEVER, Observable } from 'rxjs';
55
import { setImmediate } from './setImmediate';
66
import { isDevMode } from '@angular/core';
77
import type { IgxTheme } from '../services/theme/theme.token';
8+
import { getI18nManager } from 'igniteui-i18n-core';
89

910
/** @hidden @internal */
1011
export const ELEMENTS_TOKEN = /*@__PURE__*/new InjectionToken<boolean>('elements environment');
@@ -579,14 +580,75 @@ export const isConstructor = (ref: any) => typeof ref === 'function' && Boolean(
579580
* Similar to Angular's formatDate. However it will not throw on `undefined | null | ''` instead
580581
* coalescing to an empty string.
581582
*/
582-
export const formatDate = (value: string | number | Date, format: string, locale: string, timezone?: string): string => {
583+
export function formatDate(value: Date | string | number | null | undefined, format: string, locale: string, timezone?: string): string {
583584
if (value === null || value === undefined || value === '') {
584585
return '';
585586
}
586-
return _formatDate(value, format, locale, timezone);
587-
};
587+
if (typeof value === "string") {
588+
value = new Date(value);
589+
}
590+
const options: Intl.DateTimeFormatOptions = {
591+
timeZone: timezone
592+
};
593+
return getI18nManager().formatDateTime(value, locale, options);
594+
}
595+
596+
function parseDigitsInfo(value: string) {
597+
let minIntegerDigits = undefined, minFractionDigits = undefined, maxFractionDigits = undefined;
598+
if (value) {
599+
const parts = value.split("-");
600+
const innerParts = parts[0].split(".");
601+
if (innerParts[0] !== "1") {
602+
minIntegerDigits = parseInt(innerParts[0]);
603+
}
604+
if (innerParts.length == 2 && innerParts[1] !== "0") {
605+
minFractionDigits = parseInt(innerParts[1]);
606+
}
607+
if (parts.length == 2 && parts[1] !== "3") {
608+
maxFractionDigits = parseInt(parts[1]);
609+
}
610+
}
611+
return { minIntegerDigits, minFractionDigits, maxFractionDigits };
612+
}
588613

589-
export const formatCurrency = new CurrencyPipe(undefined).transform;
614+
function formatNumberGeneric(value: number | string | null | undefined, style?: 'decimal' | 'percent' | 'currency', locale?: string, digitsInfo?: string, currencyCode?: string, display?: 'code' | 'symbol' | 'symbol-narrow' | string) {
615+
if (value === null || value === undefined || value === '') {
616+
return '';
617+
}
618+
if (typeof value === "string") {
619+
value = parseFloat(value);
620+
}
621+
const parsedDigitsInfo = parseDigitsInfo(digitsInfo);
622+
let currencyDisplay: keyof Intl.NumberFormatOptionsCurrencyDisplayRegistry;
623+
if (display !== 'code' && display !== 'symbol' && display !== 'symbol-narrow' && display !== 'narrowSymbol' && display !== "name") {
624+
currencyDisplay = 'symbol';
625+
} else if (display === 'symbol-narrow') {
626+
currencyDisplay = 'narrowSymbol';
627+
} else {
628+
currencyCode = display || undefined;
629+
}
630+
const options: Intl.NumberFormatOptions = {
631+
style: style,
632+
currency: currencyCode,
633+
currencyDisplay: currencyDisplay,
634+
minimumIntegerDigits: parsedDigitsInfo.minIntegerDigits,
635+
minimumFractionDigits: parsedDigitsInfo.minFractionDigits,
636+
maximumFractionDigits: parsedDigitsInfo.maxFractionDigits
637+
};
638+
return getI18nManager().formatNumber(value, locale, options);
639+
}
640+
641+
export function formatNumber(value: number | string | null | undefined, locale?: string, digitsInfo?: string): string {
642+
return formatNumberGeneric(value, "decimal", locale, digitsInfo);
643+
}
644+
645+
export function formatPercent(value: number | string | null | undefined, locale?: string, digitsInfo?: string) {
646+
return formatNumberGeneric(value, "percent", locale, digitsInfo);
647+
}
648+
649+
export function formatCurrency(value: number | string | null | undefined, locale?: string, display?: 'code' | 'symbol' | 'symbol-narrow' | string, currencyCode?: string, digitsInfo?: string): string | null {
650+
return formatNumberGeneric(value, "currency", locale, digitsInfo, currencyCode, display);
651+
}
590652

591653
/** Converts pixel values to their rem counterparts for a base value */
592654
export const rem = (value: number | string) => {

projects/igniteui-angular/src/lib/data-operations/filtering-strategy.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { FilteringLogic, type IFilteringExpression } from './filtering-expression.interface';
22
import { FilteringExpressionsTree, type IFilteringExpressionsTree } from './filtering-expressions-tree';
3-
import { resolveNestedPath, parseDate, formatDate, formatCurrency, columnFieldPath } from '../core/utils';
3+
import { resolveNestedPath, parseDate, formatDate, formatCurrency, columnFieldPath, formatNumber, formatPercent } from '../core/utils';
44
import type { ColumnType, EntityType, GridType } from '../grids/common/grid.interface';
55
import { GridColumnDataType } from './data-util';
66
import { SortingDirection } from './sorting-strategy';
7-
import { formatNumber, formatPercent, getLocaleCurrencyCode } from '@angular/common';
7+
import { getLocaleCurrencyCode } from '@angular/common';
88
import type { IFilteringState } from './filtering-state.interface';
99
import { isTree } from './expressions-tree-util';
1010
import type { IgxHierarchicalGridComponent } from '../grids/hierarchical-grid/hierarchical-grid.component';
@@ -170,7 +170,7 @@ export abstract class BaseFilteringStrategy implements IFilteringStrategy {
170170
case GridColumnDataType.Time:
171171
return formatDate(value, format, locale, timezone);
172172
case GridColumnDataType.Currency:
173-
return formatCurrency(value, currencyCode || getLocaleCurrencyCode(locale), display, digitsInfo, locale);
173+
return formatCurrency(value, locale, display, currencyCode || getLocaleCurrencyCode(locale), digitsInfo);
174174
case GridColumnDataType.Number:
175175
return formatNumber(value, locale, digitsInfo);
176176
case GridColumnDataType.Percent:

projects/igniteui-angular/src/lib/date-picker/date-picker.component.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ import { IgxIconComponent } from '../icon/icon.component';
6868
import { IgxTextSelectionDirective } from '../directives/text-selection/text-selection.directive';
6969
import { getCurrentResourceStrings } from '../core/i18n/resources';
7070
import { fadeIn, fadeOut } from 'igniteui-angular/animations';
71+
import { getI18nManager } from 'igniteui-i18n-core';
7172

7273
let NEXT_ID = 0;
7374

@@ -517,6 +518,9 @@ export class IgxDatePickerComponent extends PickerBaseDirective implements Contr
517518
@Optional() @Inject(IGX_INPUT_GROUP_TYPE) _inputGroupType?: IgxInputGroupType) {
518519
super(element, _localeId, _inputGroupType);
519520
this.locale = this.locale || this._localeId;
521+
getI18nManager().onResourceChange(() => {
522+
this._resourceStrings = getCurrentResourceStrings(DatePickerResourceStringsEN, false);
523+
});
520524
}
521525

522526
/** @hidden @internal */

0 commit comments

Comments
 (0)